2010-04-06 44 views
2

使用Postgresql。触发器过程的一致性(在行触发器之前)Postgresql

我尝试使用TRIGGER过程对INSERT进行一些一致性检查。

的问题是......

是否 “BEFORE INSERT FOR EACH ROW” 可以确保每一行插入 “检查” 和 “插入” 一个又一个?我是否需要额外的表锁来保持并发插入?

检查新ROW1 - >插入ROW1 - >检查新2行 - >插入2行

-- 
-- 

-- 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

不要使用触发器,速度太慢,不可靠:许多交易可以看到在选择相同的结果,因此所有交易没问题,你的数据不会是(部分)唯一的。 – 2010-04-07 06:38:29

回答

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(); 
0

为什么你不能使用唯一的密钥来执行此操作?

+0

我想仅适用于某些特定列值的唯一约束。以上面的代码为例。如果所有产品的名称都过期,则可以多次存在相同的产品名称,但过期= false的产品必须具有唯一的名称。 – elgcom 2010-04-06 20:08:55

+1

您可以创建唯一索引作为Stephan Denne显示的部分索引。见http://www.postgresql.org/docs/8.4/interactive/indexes-partial.html – Kuberchaun 2010-04-06 22:08:23

+0

谢谢,部分索引是确切的解决方案! 但我仍然不知道Trigger“FOR EACH ROW”是否可以保证顺序UPDATE或INSERT,以便并发表INSERT或UPDATE不会违反约束。 – elgcom 2010-04-07 08:33:55