0

我编写了以下触发器来保证插入上的字段“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();

但我在数据库上重复了“文件序列”:

select id, filesequence, stakeholder from file where stakeholder=5273;
id      filesequence    stakeholder
6773    5               5273
6774    5               5273

根据我的理解,SELECT... FOR UPDATE 将锁定同一利益相关者的两个事务,然后第二个事务将读取新的“文件序列”。但它不起作用。

我在 PgAdmin 上做了一些测试,执行以下操作:

BEGIN;
select id from stakeholder where id = 5273 FOR UPDATE;

它确实锁定了其他记录被插入到同一个利益相关者。然后似乎LOCK正在工作。

但是当我运行并发上传的应用程序时,我看到然后重复。

有人可以帮我找出我的触发器有什么问题吗?

谢谢,道格拉斯。

4

1 回答 1

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;

就是这样,只需更改此行即可。

于 2013-11-07T12:18:45.293 回答