一个事务范围内的主键冲突
Primary key collision in scope of one trasaction
我有一个 postgresql
数据库,它严重依赖于来自外部的事件,例如管理员更改/添加某些字段或记录可能会触发其他 tables.
中整体字段结构的更改
然而,问题就在这里,因为有时触发函数更改的字段是主键字段。有一个table,它使用两个外键id作为主键,如下例:
# | PK id1 | PK id2 | data |
0 | 1 | 1 | ab |
1 | 1 | 2 | cd |
2 | 1 | 3 | ef |
然而,在一次交易中(如果我可以这样称呼它,因为实际上它是一个 plpgsql
函数),结构可能会更改为:
# | PK id1 | PK id2 | data |
0 | 1 | 3 | ab |
1 | 1 | 2 | cd |
2 | 1 | 1 | ef |
您可能已经注意到,将第 0 条记录的第二个主键更改为 3
,将第 2 条记录的第二个主键更改为 1
,这与之前的相反。
100%确定函数生效后不会发生任何碰撞,但我想知道,如何实现?
事实上,我可以使用合成主键作为 BIGSERIAL
,但仍然需要 UNIQUE
包含这两个 ID,因此它不会执行把戏,不幸的是。
您可以将约束声明为可延迟的,例如主键:
CREATE TABLE elbat (id int,
nmuloc int,
PRIMARY KEY (id)
DEFERRABLE);
然后您可以在事务中使用 SET CONSTRAINTS
将可延迟约束设置为已延迟。这意味着它们可以在交易期间暂时被违反,但必须在交易的 COMMIT
.
履行
假设我们的示例中有一些数据 table:
INSERT INTO elbat (id,
nmuloc)
VALUES (1,
1),
(2,
2);
我们现在可以像这样切换 ID:
BEGIN TRANSACTION;
SET CONSTRAINTS ALL DEFERRED;
UPDATE elbat
SET id = 2
WHERE nmuloc = 1;
SELECT *
FROM elbat;
UPDATE elbat
SET id = 1
WHERE nmuloc = 2;
COMMIT;
即使 ID 在第一个 UPDATE
之后都是 2
,也没有错误。
db<>fiddle
更多信息可以在文档中找到,例如在 CREATE TABLE
(or ALTER TABLE
) and SET CONSTRAINTS
.
我有一个 postgresql
数据库,它严重依赖于来自外部的事件,例如管理员更改/添加某些字段或记录可能会触发其他 tables.
然而,问题就在这里,因为有时触发函数更改的字段是主键字段。有一个table,它使用两个外键id作为主键,如下例:
# | PK id1 | PK id2 | data |
0 | 1 | 1 | ab |
1 | 1 | 2 | cd |
2 | 1 | 3 | ef |
然而,在一次交易中(如果我可以这样称呼它,因为实际上它是一个 plpgsql
函数),结构可能会更改为:
# | PK id1 | PK id2 | data |
0 | 1 | 3 | ab |
1 | 1 | 2 | cd |
2 | 1 | 1 | ef |
您可能已经注意到,将第 0 条记录的第二个主键更改为 3
,将第 2 条记录的第二个主键更改为 1
,这与之前的相反。
100%确定函数生效后不会发生任何碰撞,但我想知道,如何实现?
事实上,我可以使用合成主键作为 BIGSERIAL
,但仍然需要 UNIQUE
包含这两个 ID,因此它不会执行把戏,不幸的是。
您可以将约束声明为可延迟的,例如主键:
CREATE TABLE elbat (id int,
nmuloc int,
PRIMARY KEY (id)
DEFERRABLE);
然后您可以在事务中使用 SET CONSTRAINTS
将可延迟约束设置为已延迟。这意味着它们可以在交易期间暂时被违反,但必须在交易的 COMMIT
.
假设我们的示例中有一些数据 table:
INSERT INTO elbat (id,
nmuloc)
VALUES (1,
1),
(2,
2);
我们现在可以像这样切换 ID:
BEGIN TRANSACTION;
SET CONSTRAINTS ALL DEFERRED;
UPDATE elbat
SET id = 2
WHERE nmuloc = 1;
SELECT *
FROM elbat;
UPDATE elbat
SET id = 1
WHERE nmuloc = 2;
COMMIT;
即使 ID 在第一个 UPDATE
之后都是 2
,也没有错误。
db<>fiddle
更多信息可以在文档中找到,例如在 CREATE TABLE
(or ALTER TABLE
) and SET CONSTRAINTS
.