Supabase中如何同时创建关联的Post与Comment?
在Supabase中同时创建Post和关联Comment的实现方案
一、客户端直接用事务API实现
Supabase JS客户端从2.x版本开始支持事务操作,能实现你要的“要么全成要么全败”的原子性效果,完美替代Rails里的transaction。
你之前的代码问题在于没有正确处理异步逻辑,而且两个操作没绑定成事务,现在用客户端的事务API重写如下:
const { data, error } = await supabase.transaction(async (tx) => { // 先插入Post,获取生成的id const { data: post, error: postError } = await tx .from('posts') .insert({ title: 'new post', body: 'body of new post' }) .select('id') .single(); if (postError) throw postError; // 再插入关联的Comment const { data: comment, error: commentError } = await tx .from('comments') .insert({ post_id: post.id, body: 'comment body' }); if (commentError) throw commentError; return { post, comment }; }); if (error) { console.error('事务失败:', error); } else { console.log('Post和Comment创建成功:', data); }
只要其中任何一步失败,整个事务就会回滚,不会出现只有Post没有Comment的情况。
二、用PostgreSQL函数+Supabase RPC实现
如果想把逻辑放在数据库层面(更安全,避免客户端操作的疏漏),可以创建一个数据库函数,再通过Supabase的rpc()方法调用。
1. 创建数据库函数
在Supabase的SQL编辑器里执行这段代码:
CREATE OR REPLACE FUNCTION create_post_with_comment(p_title text, p_post_body text, p_comment_body text) RETURNS TABLE(post_id bigint, comment_id bigint) AS $$ BEGIN BEGIN -- 插入Post并获取id INSERT INTO posts(title, body) VALUES(p_title, p_post_body) RETURNING id INTO post_id; -- 插入关联的Comment INSERT INTO comments(post_id, body) VALUES(post_id, p_comment_body) RETURNING id INTO comment_id; RETURN NEXT; EXCEPTION WHEN OTHERS THEN RAISE; END; END; $$ LANGUAGE plpgsql SECURITY DEFINER;
2. 客户端调用RPC
const { data, error } = await supabase.rpc('create_post_with_comment', { p_title: 'new post', p_post_body: 'body of new post', p_comment_body: 'comment body' }); if (error) { console.error('创建失败:', error); } else { console.log('创建成功:', data); }
数据库函数本身自带事务性,只要有一步出错就会自动回滚,完全符合你的需求。
三、额外加固:防止Post变成无评论状态
如果要彻底确保业务规则,还可以给数据库加个触发器,禁止删除某篇Post的最后一条Comment:
CREATE OR REPLACE FUNCTION prevent_last_comment_delete() RETURNS TRIGGER AS $$ DECLARE comment_count integer; BEGIN SELECT COUNT(*) INTO comment_count FROM comments WHERE post_id = OLD.post_id; IF comment_count = 1 THEN RAISE EXCEPTION '不能删除帖子的最后一条评论'; END IF; RETURN OLD; END; $$ LANGUAGE plpgsql; CREATE TRIGGER trigger_prevent_last_comment_delete BEFORE DELETE ON comments FOR EACH ROW EXECUTE FUNCTION prevent_last_comment_delete();
这样用户就没法把某篇Post的评论删光,从根源上保证你的业务逻辑。
内容的提问来源于stack exchange,提问作者Sventies
相关产品推荐
相关产品推荐

