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

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.

Ste*_*nne 6

您的示例可以使用唯一索引完成:

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)