使用Postgresql。
我尝试使用TRIGGER程序对INSERT进行一些一致性检查。
问题是......
是否“在插入每行之前”是否可以确保每行插入“已检查”和“插入”一个接一个?我是否需要在桌面上额外锁定才能从并发插入中生存?
检查新的row1 - > insert 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!
这没关系
name | expired
==============
p1 | true
p1 | true
p1 | false
这不行
name | expired
==============
p1 | true
p1 | false
p1 | false
或者我应该问, 如何使用Trigger实现“主要”或“唯一”约束类SQL。
答案 0 :(得分:6)
您的示例可以使用唯一索引来完成:
CREATE UNIQUE INDEX uq_check_consistency ON product ( name ) WHERE NOT expired;
这将导致第二个事务中的一个语句可能会导致约束,阻塞直到第一个事务提交或回滚。
已编辑添加:
要使用触发器获得类似(或更复杂)的事务安全行为,您可以创建一个延迟到事务提交时间的CONSTRAINT
trigger。这些触发函数需要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();
答案 1 :(得分:0)
为什么不能使用唯一键来强制执行此操作?