Supabase数据库触发器 #
一、触发器概述 #
1.1 什么是触发器 #
text
触发器特点
├── 自动执行的函数
├── 响应数据库事件
├── BEFORE/AFTER触发
├── 每行或每语句触发
└── 用于数据验证、审计、同步
1.2 触发时机 #
| 时机 | 说明 |
|---|---|
| BEFORE | 操作前执行 |
| AFTER | 操作后执行 |
| INSTEAD OF | 替代操作(视图) |
1.3 触发事件 #
| 事件 | 说明 |
|---|---|
| INSERT | 插入时 |
| UPDATE | 更新时 |
| DELETE | 删除时 |
| TRUNCATE | 清空时 |
二、创建触发器 #
2.1 基础语法 #
sql
-- 1. 创建触发器函数
CREATE OR REPLACE FUNCTION trigger_function()
RETURNS TRIGGER AS $$
BEGIN
-- 触发器逻辑
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
-- 2. 创建触发器
CREATE TRIGGER trigger_name
BEFORE INSERT ON table_name
FOR EACH ROW
EXECUTE FUNCTION trigger_function();
2.2 自动更新时间戳 #
sql
-- 创建触发器函数
CREATE OR REPLACE FUNCTION update_updated_at()
RETURNS TRIGGER AS $$
BEGIN
NEW.updated_at = NOW();
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
-- 创建触发器
CREATE TRIGGER set_updated_at
BEFORE UPDATE ON posts
FOR EACH ROW
EXECUTE FUNCTION update_updated_at();
2.3 自动创建用户资料 #
sql
CREATE OR REPLACE FUNCTION handle_new_user()
RETURNS TRIGGER AS $$
BEGIN
INSERT INTO public.profiles (id, email, full_name)
VALUES (
NEW.id,
NEW.email,
NEW.raw_user_meta_data->>'full_name'
);
RETURN NEW;
END;
$$ LANGUAGE plpgsql SECURITY DEFINER;
CREATE TRIGGER on_auth_user_created
AFTER INSERT ON auth.users
FOR EACH ROW
EXECUTE FUNCTION handle_new_user();
三、触发器函数 #
3.1 NEW和OLD变量 #
sql
CREATE OR REPLACE FUNCTION log_changes()
RETURNS TRIGGER AS $$
BEGIN
IF TG_OP = 'INSERT' THEN
-- NEW: 新插入的行
INSERT INTO audit_log (action, record_id, new_data)
VALUES ('INSERT', NEW.id, to_jsonb(NEW));
ELSIF TG_OP = 'UPDATE' THEN
-- OLD: 更新前的行
-- NEW: 更新后的行
INSERT INTO audit_log (action, record_id, old_data, new_data)
VALUES ('UPDATE', NEW.id, to_jsonb(OLD), to_jsonb(NEW));
ELSIF TG_OP = 'DELETE' THEN
-- OLD: 被删除的行
INSERT INTO audit_log (action, record_id, old_data)
VALUES ('DELETE', OLD.id, to_jsonb(OLD));
END IF;
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
3.2 条件触发 #
sql
CREATE OR REPLACE FUNCTION notify_price_change()
RETURNS TRIGGER AS $$
BEGIN
-- 只在价格变化时触发
IF OLD.price IS DISTINCT FROM NEW.price THEN
INSERT INTO price_history (product_id, old_price, new_price)
VALUES (NEW.id, OLD.price, NEW.price);
END IF;
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
CREATE TRIGGER track_price_changes
AFTER UPDATE ON products
FOR EACH ROW
EXECUTE FUNCTION notify_price_change();
3.3 数据验证 #
sql
CREATE OR REPLACE FUNCTION validate_post()
RETURNS TRIGGER AS $$
BEGIN
-- 验证标题长度
IF LENGTH(NEW.title) < 5 THEN
RAISE EXCEPTION 'Title must be at least 5 characters';
END IF;
-- 自动生成slug
IF NEW.slug IS NULL THEN
NEW.slug := LOWER(REGEXP_REPLACE(NEW.title, '[^a-zA-Z0-9]', '-', 'g'));
END IF;
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
CREATE TRIGGER validate_post_before_insert
BEFORE INSERT OR UPDATE ON posts
FOR EACH ROW
EXECUTE FUNCTION validate_post();
四、常用触发器示例 #
4.1 审计日志 #
sql
CREATE TABLE audit_log (
id BIGSERIAL PRIMARY KEY,
table_name TEXT NOT NULL,
action TEXT NOT NULL,
record_id TEXT,
old_data JSONB,
new_data JSONB,
user_id UUID,
created_at TIMESTAMPTZ DEFAULT NOW()
);
CREATE OR REPLACE FUNCTION audit_trigger()
RETURNS TRIGGER AS $$
BEGIN
INSERT INTO audit_log (table_name, action, record_id, old_data, new_data, user_id)
VALUES (
TG_TABLE_NAME,
TG_OP,
COALESCE(NEW.id::TEXT, OLD.id::TEXT),
CASE WHEN TG_OP IN ('UPDATE', 'DELETE') THEN to_jsonb(OLD) END,
CASE WHEN TG_OP IN ('INSERT', 'UPDATE') THEN to_jsonb(NEW) END,
auth.uid()
);
RETURN COALESCE(NEW, OLD);
END;
$$ LANGUAGE plpgsql SECURITY DEFINER;
-- 应用到表
CREATE TRIGGER posts_audit
AFTER INSERT OR UPDATE OR DELETE ON posts
FOR EACH ROW
EXECUTE FUNCTION audit_trigger();
4.2 维护统计表 #
sql
CREATE TABLE user_stats (
user_id UUID PRIMARY KEY,
posts_count INTEGER DEFAULT 0,
comments_count INTEGER DEFAULT 0,
last_post_at TIMESTAMPTZ
);
CREATE OR REPLACE FUNCTION update_user_stats()
RETURNS TRIGGER AS $$
BEGIN
IF TG_OP = 'INSERT' THEN
INSERT INTO user_stats (user_id, posts_count, last_post_at)
VALUES (NEW.author_id, 1, NEW.created_at)
ON CONFLICT (user_id) DO UPDATE
SET
posts_count = user_stats.posts_count + 1,
last_post_at = NEW.created_at;
ELSIF TG_OP = 'DELETE' THEN
UPDATE user_stats
SET posts_count = posts_count - 1
WHERE user_id = OLD.author_id;
END IF;
RETURN COALESCE(NEW, OLD);
END;
$$ LANGUAGE plpgsql;
CREATE TRIGGER update_posts_stats
AFTER INSERT OR DELETE ON posts
FOR EACH ROW
EXECUTE FUNCTION update_user_stats();
4.3 软删除 #
sql
CREATE OR REPLACE FUNCTION soft_delete()
RETURNS TRIGGER AS $$
BEGIN
-- 不实际删除,而是设置deleted_at
UPDATE posts
SET deleted_at = NOW()
WHERE id = OLD.id;
RETURN NULL; -- 阻止实际删除
END;
$$ LANGUAGE plpgsql;
CREATE TRIGGER posts_soft_delete
BEFORE DELETE ON posts
FOR EACH ROW
EXECUTE FUNCTION soft_delete();
4.4 全文搜索索引 #
sql
CREATE OR REPLACE FUNCTION update_search_vector()
RETURNS TRIGGER AS $$
BEGIN
NEW.search_vector :=
setweight(to_tsvector('english', COALESCE(NEW.title, '')), 'A') ||
setweight(to_tsvector('english', COALESCE(NEW.content, '')), 'B');
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
CREATE TRIGGER posts_search_vector
BEFORE INSERT OR UPDATE ON posts
FOR EACH ROW
EXECUTE FUNCTION update_search_vector();
五、管理触发器 #
5.1 查看触发器 #
sql
-- 查看表的所有触发器
SELECT
trigger_name,
event_manipulation,
action_timing,
action_statement
FROM information_schema.triggers
WHERE event_object_table = 'posts';
5.2 禁用/启用触发器 #
sql
-- 禁用特定触发器
ALTER TABLE posts DISABLE TRIGGER posts_audit;
-- 禁用所有触发器
ALTER TABLE posts DISABLE TRIGGER ALL;
-- 启用触发器
ALTER TABLE posts ENABLE TRIGGER posts_audit;
ALTER TABLE posts ENABLE TRIGGER ALL;
5.3 删除触发器 #
sql
DROP TRIGGER IF EXISTS trigger_name ON table_name;
六、触发器变量 #
6.1 特殊变量 #
sql
CREATE OR REPLACE FUNCTION trigger_info()
RETURNS TRIGGER AS $$
BEGIN
RAISE NOTICE 'Table: %', TG_TABLE_NAME;
RAISE NOTICE 'Schema: %', TG_TABLE_SCHEMA;
RAISE NOTICE 'Operation: %', TG_OP;
RAISE NOTICE 'When: %', TG_WHEN;
RAISE NOTICE 'Level: %', TG_LEVEL;
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
七、最佳实践 #
7.1 性能考虑 #
text
触发器性能建议
├── 避免复杂操作
├── 避免递归触发
├── 使用条件减少执行
├── 考虑批量操作影响
└── 必要时禁用触发器
7.2 调试技巧 #
sql
CREATE OR REPLACE FUNCTION debug_trigger()
RETURNS TRIGGER AS $$
BEGIN
RAISE NOTICE 'Trigger fired: % on %', TG_OP, TG_TABLE_NAME;
RAISE NOTICE 'OLD: %', OLD;
RAISE NOTICE 'NEW: %', NEW;
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
八、总结 #
触发器要点:
| 操作 | SQL |
|---|---|
| 创建函数 | CREATE FUNCTION … RETURNS TRIGGER |
| 创建触发器 | CREATE TRIGGER … |
| 禁用 | ALTER TABLE … DISABLE TRIGGER |
| 删除 | DROP TRIGGER … |
下一步,让我们学习全文搜索!
最后更新:2026-03-28