Skip to content

触发器 ​

核心问题:如何使用触发器?BEFORE/AFTER 触发器有什么区别?如何实现审计日志?

1. 基本触发器 ​

sql
-- 自动更新 updated_at 字段
CREATE OR REPLACE FUNCTION update_timestamp()
RETURNS TRIGGER AS $$
BEGIN
    NEW.updated_at = NOW();
    RETURN NEW;
END;
$$ LANGUAGE plpgsql;

CREATE TRIGGER trg_update_timestamp
    BEFORE UPDATE ON users
    FOR EACH ROW
    EXECUTE FUNCTION update_timestamp();

2. 审计日志触发器 ​

sql
CREATE OR REPLACE FUNCTION audit_trigger_func()
RETURNS TRIGGER AS $$
BEGIN
    IF TG_OP = 'INSERT' THEN
        INSERT INTO audit_log (table_name, operation, new_data, changed_at)
        VALUES (TG_TABLE_NAME, 'INSERT', to_jsonb(NEW), NOW());
        RETURN NEW;
    ELSIF TG_OP = 'UPDATE' THEN
        INSERT INTO audit_log (table_name, operation, old_data, new_data, changed_at)
        VALUES (TG_TABLE_NAME, 'UPDATE', to_jsonb(OLD), to_jsonb(NEW), NOW());
        RETURN NEW;
    ELSIF TG_OP = 'DELETE' THEN
        INSERT INTO audit_log (table_name, operation, old_data, changed_at)
        VALUES (TG_TABLE_NAME, 'DELETE', to_jsonb(OLD), NOW());
        RETURN OLD;
    END IF;
END;
$$ LANGUAGE plpgsql;

CREATE TRIGGER trg_users_audit
    AFTER INSERT OR UPDATE OR DELETE ON users
    FOR EACH ROW
    EXECUTE FUNCTION audit_trigger_func();

3. 条件触发器 ​

sql
-- 只在特定列变化时触发
CREATE OR REPLACE FUNCTION notify_price_change()
RETURNS TRIGGER AS $$
BEGIN
    IF OLD.price IS DISTINCT FROM NEW.price THEN
        PERFORM pg_notify('price_change',
            json_build_object('id', NEW.id, 'old_price', OLD.price, 'new_price', NEW.price)::text);
    END IF;
    RETURN NEW;
END;
$$ LANGUAGE plpgsql;

4. 触发器 + NOTIFY 实现实时通知 ​

sql
-- 当订单状态变化时通知应用
CREATE OR REPLACE FUNCTION notify_order_change()
RETURNS TRIGGER AS $$
BEGIN
    PERFORM pg_notify('order_changes', json_build_object(
        'operation', TG_OP,
        'order_id', NEW.id,
        'status', NEW.status,
        'user_id', NEW.user_id
    )::text);
    RETURN NEW;
END;
$$ LANGUAGE plpgsql;

CREATE TRIGGER trg_order_notify
    AFTER INSERT OR UPDATE ON orders
    FOR EACH ROW
    EXECUTE FUNCTION notify_order_change();

5. 触发器变量 ​

变量说明
NEWINSERT/UPDATE 时的新行数据
OLDUPDATE/DELETE 时的旧行数据
TG_OP操作类型:'INSERT'、'UPDATE'、'DELETE'
TG_TABLE_NAME触发器所在的表名
TG_WHEN'BEFORE'、'AFTER'、'INSTEAD OF'

6. BEFORE vs AFTER 触发器 ​

类型时机可修改 NEW典型用途
BEFORE在操作执行前✅ 可以数据验证、自动填充字段
AFTER在操作执行后❌ 不可以审计日志、通知、级联操作

7. 注意事项 ​

  • 触发器中的异常会回滚整个事务
  • 触发器执行有性能开销,避免在高频表上使用过多触发器
  • 触发器的执行顺序:BEFORE → 行操作 → AFTER
  • 同一表上多个同类型触发器按字母顺序执行

Released under the MIT License.