Postgres循环id序列

时间:2014-02-24 12:41:58

标签: database postgresql locking

说我有桌子:

CREATE TABLE custom_sequence (
  name       TEXT NOT NULL,
  number     INTEGER DEFAULT NULL,
  is_expired BOOLEAN DEFAULT FALSE
);

在插入时,我必须找到第一个过期的号码并将其放入新记录中。

例如:

"a"   1    FALSE
"b"   2     TRUE
"c"   3    FALSE

插入新内容:

"c"   2    FALSE

我可以使用TRIGGER做到这一点:

CREATE OR REPLACE FUNCTION write_custom_number()
  RETURNS TRIGGER AS
  $$
  DECLARE
    next_number INTEGER;
  BEGIN

    SELECT
      CASE
      WHEN count(*) > 0 THEN min(number)
      WHEN count(*) = 0 THEN
        CASE
        WHEN (SELECT
                count(*)
              FROM custom_sequence) > 0
        THEN (SELECT
                count(*)
              FROM custom_sequence) + 1
        WHEN (SELECT
                count(*)
              FROM custom_sequence) = 0
        THEN
          1
        END
      END
    INTO next_number
    FROM custom_sequence
    WHERE is_expired = TRUE;


    IF next_number IS NULL
    THEN
      next_number = 1;
    END IF;

    NEW.number := next_number;

    RETURN NEW;
  END
  $$
LANGUAGE plpgsql;

CREATE TRIGGER write_custom_number
BEFORE INSERT ON custom_sequence FOR EACH ROW
EXECUTE PROCEDURE write_custom_number();

但是我需要为每个INSERT锁定表格!有没有更好的方法来解决这个问题?

1 个答案:

答案 0 :(得分:1)

不,没有解决方法。它是你想要的固有的。您不能重复使用第一个过期的数字并且仍然具有并发性,因为其他人可能会在您提交之前将其插入并插入。

为了使这个并发,您需要某种全局序列管理器,它可以跟踪它已经分发的ID并对表进行脏读以查看其状态。在数据库引擎中没有类似的东西,你无法在SQL级别上执行此操作。它也很难做对。

所以没有。如果您想重新使用ID,则必须按顺序进行交易。