我编写了以下触发器,以确保插件上的字段'filesequence'始终为一个利益相关者接收最大值+ 1.
CREATE OR REPLACE FUNCTION update_filesequence()
RETURNS TRIGGER AS '
DECLARE
lastSequence file.filesequence%TYPE;
BEGIN
IF (NEW.filesequence IS NULL) THEN
PERFORM ''SELECT id FROM stakeholder WHERE id = NEW.stakeholder FOR UPDATE'';
SELECT max(filesequence) INTO lastSequence FROM file WHERE stakeholder = NEW.stakeholder;
IF (lastSequence IS NULL) THEN
lastSequence = 0;
END IF;
lastSequence = lastSequence + 1;
NEW.filesequence = lastSequence;
END IF;
RETURN NEW;
END;
' LANGUAGE 'plpgsql';
CREATE TRIGGER file_update_filesequence BEFORE INSERT
ON file FOR EACH ROW EXECUTE PROCEDURE
update_filesequence();
但我在数据库上重复'filesequence':
select id, filesequence, stakeholder from file where stakeholder=5273;
id filesequence stakeholder
6773 5 5273
6774 5 5273
通过我的承诺,SELECT ... FOR UPDATE将锁定同一个利益相关者的两个事务,然后第二个将读取新的“filesequence”。但它没有用。
我对PgAdmin进行了一些测试,执行以下操作:
BEGIN;
select id from stakeholder where id = 5273 FOR UPDATE;
它真的锁定了其他记录被插入同一个利益相关者。然后似乎LOCK正在工作。
但是当我使用并发上传运行应用程序时,我会看到重复。
有人可以帮助我找到触发器的问题吗?
谢谢, 道格拉斯。
答案 0 :(得分:1)
你的想法是对的。要根据另一个字段获取自动增量(让它说它指定给一个组)你不能使用序列,那么你必须在增加它之前锁定该组的行。
触发器功能的逻辑就是这样。但是您对PERFORM
操作有误解。它应该被放置而不是SELECT
关键字,因此它不会接收字符串作为参数。这意味着当你这样做时:
PERFORM 'SELECT id FROM stakeholder WHERE id = NEW.stakeholder FOR UPDATE';
PL / pgSQL实际上正在执行:
SELECT 'SELECT id FROM stakeholder WHERE id = NEW.stakeholder FOR UPDATE';
忽略了结果。
你需要做的就是:
PERFORM id FROM stakeholder WHERE id = NEW.stakeholder FOR UPDATE;
就是这样,只改变这一行,你就完成了。