一笔交易范围内的主键冲突

问题描述

我有一个 (enter code here) mRef.child("users").addListenerForSingleValueEvent(object : ValueEventListener{ override fun onDataChange(snapshot: DataSnapshot) { if (snapshot!!.getValue()!= null){ for (user in snapshot.children){ var sanMar=user.getValue(Users::class.java) button4.setonClickListener { textView13.text="${sanMar!!.user_id}" textView14.text="${sanMar!!.adiSoyadi}" textView15.text="${sanMar!!.phoneNumber}" 数据库,它严重依赖外部事件,例如管理员更改/添加某些字段或记录可能会触发其他表中整体字段结构的更改。

然而,问题在于,有时触发器函数更改的字段是主键字段。有一个表,它使用两个外键 id 作为主键,如下例所示:

postgresql

但是,在一个事务中(如果我可以这样称呼它,因为实际上它是一个 # | PK id1 | PK id2 | data | 0 | 1 | 1 | ab | 1 | 1 | 2 | cd | 2 | 1 | 3 | ef | 函数),结构可能会更改为:

plpgsql

您可能已经注意到,将第 0 条记录的第二个主键更改为 # | PK id1 | PK id2 | data | 0 | 1 | 3 | ab | 1 | 1 | 2 | cd | 2 | 1 | 1 | ef | ,将第 2 条记录的第二个主键更改为 3,这与之前相反。

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

事实上,我可以使用合成主键作为 1,但仍然需要包含 BIGSERIAL 这两个 ID,所以它不会成功,不幸的是。

解决方法

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

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 在第一个 2 之后都是 UPDATE,也没有错误。
db<>fiddle

更多信息可以在文档中找到,例如在 CREATE TABLE(或 ALTER TABLE)和 SET CONSTRAINTS 中。