使用 EXCLUDE 约束对范围进行读/写锁定

问题描述 投票:0回答:1

我有一张桌子:

CREATE EXTENSION btree_gist;
CREATE TABLE excllock (
  id BIGSERIAL PRIMARY KEY,
  myrange INT8RANGE NOT NULL,
  key UUID NOT NULL,
  isread BOOLEAN NOT NULL,
  EXCLUDE USING gist (
    myrange WITH &&,
    key WITH =
  )
);

我希望它有这样的行为:

  • 可以添加
    myrange
    上重叠
    key
    的多行,只要它们全部都是
    isread
  • 如果添加带有
    isread=FALSE
    的新行,则会发生以下三种情况之一:
    1. 数据库中已经存在至少一行
      isread
      行,因此约束应该失败(并发读取访问已经存在,无法写入)。
    2. 已经存在
      isread=FALSE
      行,因此约束失败(并发写访问已经存在,无法写入)。
    3. 没有行匹配排除约束:该行已添加(无并发访问,可以写入)。

因此实际上一次只能有多个

isread=TRUE
或一个
isread=FALSE
(或者根本没有匹配
(key, myrange)
的记录),本质上是在键范围对上创建一个读/写锁。

示例:

-- Insert multiple read locks (allowed)
INSERT INTO excllock (myrange, key, isread) VALUES ('[1,10)', '00000000-0000-0000-0000-000000000001', TRUE);
INSERT INTO excllock (myrange, key, isread) VALUES ('[5,15)', '00000000-0000-0000-0000-000000000001', TRUE);

-- Try inserting a write lock (should fail due to read locks)
INSERT INTO excllock (myrange, key, isread) VALUES ('[1,10)', '00000000-0000-0000-0000-000000000001', FALSE);

-- Insert a write lock on a free range
INSERT INTO excllock (myrange, key, isread) VALUES ('[100,1000)', '00000000-0000-0000-0000-000000000001', FALSE);

-- Try to insert a read lock inside the write range (should fail)
INSERT INTO excllock (myrange, key, isread) VALUES ('[105,900)', '00000000-0000-0000-0000-000000000001', TRUE);

我想过使用

where (NOT isread)
,但它会完全忽略
isread
行。

有没有一种巧妙的方法来创建这种约束?

postgresql constraints exclusion-constraint
1个回答
0
投票

这可以通过在排除约束中添加一个附加参数来表示锁的读/写状态来实现。我已经对一个读锁进行了建模,其范围仅包含该行的 id,保证该行的唯一性并且永远不会与任何其他行的 id 重叠。然后,我使用无限范围来表示写锁,该写锁将与所有其他范围重叠,无论它们表示读锁还是写锁。

CREATE TABLE excllock (
  id BIGSERIAL PRIMARY KEY,
  myrange INT8RANGE NOT NULL,
  key UUID NOT NULL,
  isread BOOLEAN NOT NULL,
  EXCLUDE USING gist (
    myrange WITH &&,
    key WITH =,
    (CASE WHEN isread THEN int8range(id, id, '[]')
                      ELSE int8range(null, null) END) WITH &&
  )
);
© www.soinside.com 2019 - 2024. All rights reserved.