rnd*_*gen 2 postgresql triggers stored-procedures
使用Postgresql.
我尝试使用TRIGGER程序对INSERT进行一些一致性检查.
问题是 ......
是否"在插入每行之前"是否可以确保每行插入"已检查"和"插入"一个接一个?我是否需要在桌面上额外锁定才能从并发插入中生存?
检查新的row1 - >插入row1 - >检查新的row2 - >插入row2
--
--
-- unexpired product name is unique.
CREATE TABLE product (
"name" VARCHAR(100) NOT NULL,
"expired" BOOLEAN NOT NULL
);
CREATE OR REPLACE FUNCTION check_consistency() RETURNS TRIGGER AS $$
BEGIN
IF EXISTS (SELECT * FROM product WHERE name=NEW.name AND expired='false') THEN
RAISE EXCEPTION 'duplicated!!!';
END IF;
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
CREATE TRIGGER trigger_check_consistency
BEFORE INSERT ON product
FOR EACH ROW EXECUTE PROCEDURE check_consistency();
--
INSERT INTO product VALUES("prod1", true);
INSERT INTO product VALUES("prod1", false);
INSERT INTO product VALUES("prod1", false); // exception!
Run Code Online (Sandbox Code Playgroud)
还行吧
name | expired
==============
p1 | true
p1 | true
p1 | false
Run Code Online (Sandbox Code Playgroud)
这不行
name | expired
==============
p1 | true
p1 | false
p1 | false
Run Code Online (Sandbox Code Playgroud)
或者我应该问,我如何使用Trigger来实现"主要"或"唯一"类似约束的SQL.
您的示例可以使用唯一索引完成:
CREATE UNIQUE INDEX uq_check_consistency ON product ( name ) WHERE NOT expired;
Run Code Online (Sandbox Code Playgroud)
这将导致第二个事务中的语句可能会导致约束,阻塞直到第一个事务提交或回滚.
编辑添加:
要使用触发器获得类似(或更复杂)的事务安全行为,您可以创建一个延迟到事务提交时间的CONSTRAINT
触发器.这些触发器函数需要是AFTER
触发器,检查您的约束是否已被违反:
CREATE OR REPLACE FUNCTION after_check_consistency() RETURNS TRIGGER AS $$
BEGIN
IF (SELECT count(*) FROM product WHERE name=NEW.name AND expired='false') > 1 THEN
RAISE EXCEPTION 'duplicated!!!';
END IF;
RETURN NULL;
END;
$$ LANGUAGE plpgsql;
CREATE CONSTRAINT TRIGGER trigger_check_consistency
AFTER INSERT OR UPDATE ON product
DEFERRABLE INITIALLY DEFERRED
FOR EACH ROW EXECUTE PROCEDURE after_check_consistency();
Run Code Online (Sandbox Code Playgroud)