触发过程的一致性(行触发前)Postgresql

时间:2010-04-06 18:23:21

标签: postgresql stored-procedures triggers

使用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。

2 个答案:

答案 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)

为什么不能使用唯一键来强制执行此操作?