在某些情况下,UPDATE事务可以失败而不是阻塞等待“ FOR UPDATE lock”吗?

时间:2018-07-20 19:20:23

标签: postgresql postgresql-9.6

我正在使用Postgres 9.6.5。

文档说:

  

13.3. Explicit Locking

     

13.3.2。行级锁定”->“行级锁定模式”->“更新”:

     

FOR UPDATE导致SELECT语句检索的行被锁定,就像更新一样。这样可以防止它们被其他事务锁定,修改或删除,直到当前事务结束为止。也就是说,将阻止其他尝试进行这些行的UPDATE,DELETE,SELECT FOR UPDATE,SELECT FOR NO KEY UPDATE,SELECT FOR SHARE或SELECT FOR KEY SHARE的事务,直到当前事务结束为止。相反,SELECT FOR UPDATE将等待在同一行上运行了任何这些命令的并发事务,然后将锁定并返回更新的行(如果删除了该行,则不返回任何行)。 ...

     

该模式还可以通过行上的任何DELETE以及修改某些列上的值的UPDATE来获取。当前,在UPDATE情况下考虑使用的列集是可以在外键上使用的唯一索引(因此不考虑部分索引和表达式索引),但是将来可能会改变。

关于在另一个事务中通过“ SELECT FOR UPDATE”锁定的行上的UPDATE,我阅读以下内容:尝试对这些行进行UPDATE的其他事务将被阻止,直到当前事务(执行“ SELECT FOR UPDATE”对于这些行)结束,除非这些行中被更新的列是那些没有唯一索引可用于外键的列。

这是正确的吗?如果是这样,如果我有一个带有文本列“ stage”的表“ program”(此列不适合“在它们上具有可用于外键的唯一索引”),并且我有一个事务在某些行上执行“ SELECT FOR UPDATE”,然后在这些行中执行UPDATE的“阶段”,是否正确?在这些行上进行UPDATE的“阶段”的其他并发事务可能会失败,而不是阻塞直到前一个事务结束? >

1 个答案:

答案 0 :(得分:0)

如果在UPDATESELECT...FOR UPDATE之一中检测到死锁,您的事务可能会失败,例如:

交易1

BEGIN; SELECT * FROM T1 FOR UPDATE; SELECT * FROM T2 FOR UPDATE; -- Intentionally, no rollback nor commit yet

交易2

BEGIN; SELECT * FROM T2 FOR UPDATE; -- blocks T2 first SELECT * FROM T1 FOR UPDATE; -- exception will happen here

第二笔交易试图锁定T1时,您会得到:

ERROR: 40P01: deadlock detected DETAIL: Process 15981 waits for ShareLock on transaction 3538264; blocked by process 15942. Process 15942 waits for ShareLock on transaction 3538265; blocked by process 15981. HINT: See server log for query details. CONTEXT: while locking tuple (0,1) in relation "t1" LOCATION: DeadLockReport, deadlock.c:956 Time: 1001.728 ms