postgres - trigger before transaction commit
我想知道是否间接可能在事务即将提交之前执行触发器? 在此触发器中,我将执行一致性检查并在需要时回滚事务。
例如,我有三个表:
1 2 3 | users (id, name) groups (id, name) user_in_group (user_id, group_id) |
我想创建一个触发器,用于验证用户是否始终是组的一部分。 不允许孤儿用户。 每次插入用户时,此触发器将验证是否还发生了进入user_in_group的相应插入。 如果不是,则事务不会提交。
这不能使用简单的基于行或语句的触发器来完成,因为上述场景需要两个单独的语句。
反过来,当从user_in_group中删除时,可以通过基于行的触发器轻松完成。
您是否使用
真正的方法不是真的要在数据库中建立约束吗?这似乎正是约束的目的。添加一个外键约束和一个非null,看起来你应该在业务中。
现在修改了对称约束:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | DROP TABLE foousers cascade; DROP TABLE foogroups cascade; DROP TABLE foousergrps cascade; CREATE TABLE foousers (id INT PRIMARY KEY, name text); CREATE TABLE foogroups (id INT PRIMARY KEY, name text); CREATE TABLE foousergrps (user_id INT UNIQUE REFERENCES foousers NOT NULL, group_id INT UNIQUE REFERENCES foogroups NOT NULL); ALTER TABLE foogroups ADD FOREIGN KEY (id) REFERENCES foousergrps (group_id) deferrable initially deferred; ALTER TABLE foousers ADD FOREIGN KEY (id) REFERENCES foousergrps (user_id) deferrable initially deferred; BEGIN; INSERT INTO foousers VALUES (0, 'root'); INSERT INTO foousers VALUES (1, 'daemon'); INSERT INTO foogroups VALUES (0, 'wheel'); INSERT INTO foogroups VALUES (1, 'daemon'); INSERT INTO foousergrps VALUES (0,0); INSERT INTO foousergrps VALUES (1,1); commit; |
禁止:
1 2 | INSERT INTO foousers VALUES (2, 'bad'); INSERT INTO foousergrps VALUES (2,2); |
(不可延迟,嘘)检查功能的示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 | CREATE TABLE foousergrps (user_id INT UNIQUE REFERENCES foousers NOT NULL, group_id INT NOT NULL); CREATE FUNCTION fooorphangroupcheck(INT) RETURNS BOOLEAN AS $$ DECLARE gid alias FOR $1; BEGIN perform 1 FROM foousergrps WHERE group_id = gid LIMIT 1; IF NOT FOUND THEN RETURN FALSE; END IF; RETURN TRUE; END; $$ LANGUAGE 'plpgsql'; ALTER TABLE foogroups ADD CHECK (fooorphangroupcheck(id)); |
看看文档,似乎没有这样的触发选项......所以实现"无孤儿用户"规则的一种方法是不允许直接插入
或者只允许通过存储过程插入新用户,该存储过程将所有必需数据作为inpud,因此不允许用户使用组。
顺便说一句,为什么你有单独的用户和组关系表?为什么不将
您可以使用sql
1 2 3 4 5 6 7 8 | WITH insert_user AS ( INSERT INTO users(name) VALUES ('bla-bla-user') RETURNING id ) INSERT INTO user_in_group(user_id, group_id) SELECT id, 999 FROM insert_user UNION SELECT id, 888 FROM insert_user; SELECT groups (id, name) user_in_group (user_id, group_id) |
来自文档。 。 。
Triggers can be defined to execute either before or after any INSERT,
UPDATE, or DELETE operation, either once per modified row, or once per
SQL statement.