【问题标题】:Primary key collision in scope of one trasaction一个事务范围内的主键冲突
【发布时间】:2020-12-21 00:03:14
【问题描述】:

我有一个postgresql 数据库,它严重依赖外部事件,例如管理员更改/添加某些字段或记录可能会触发其他表中整体字段结构的更改。

然而,问题就在于此,因为有时触发函数更改的字段是主键字段。有一个表,它使用两个外键 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,将第二条记录的第二个主键更改为 1,这与之前的相反。

100%确定函数生效后不会发生任何冲突,但我想知道,如何实现?

事实上,我可以使用合成主键作为 BIGSERIAL,但仍然需要将这两个 id 包含在 UNIQUE 中,所以很遗憾,它不会起作用。

【问题讨论】:

    标签: sql database postgresql foreign-keys primary-key


    【解决方案1】:

    您可以将约束声明为可延迟的,例如主键:

    CREATE TABLE elbat (id int,
                        nmuloc int,
                        PRIMARY KEY (id)
                                    DEFERRABLE);
    

    然后您可以在事务中使用SET CONSTRAINTS 将可延期约束设置为延期。这意味着它们可以在交易期间暂时被违反,但必须在交易的COMMIT 处履行。

    假设我们的示例表中有一些数据:

    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(或ALTER TABLE)和SET CONSTRAINTS

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-07-01
      • 2014-02-24
      • 2013-08-25
      • 2021-09-25
      • 2015-05-26
      • 1970-01-01
      相关资源
      最近更新 更多