如何避免更新死锁

How to Avoid update deadlock

在使用 Postgres JDBC 工作时...

隔离级别="Read committed"

当我尝试在一些操作后更新 table 时,我在多线程环境中遇到了同样的死锁。 所以我尝试使用多个查询,如下所示

  ps = con.prepareStatement("UPDATE TableA SET column1=column1-? WHERE column2=? and column3=?;"  
                          + "UPDATE TableA SET column1=column1+? WHERE column2=? and column3=?;");

这是错误的 postgresql 日志

2016-12-19 12:25:44 IST STATEMENT:  UPDATE TableA SET column1=column1+ WHERE column2= and column3=
2016-12-19 12:25:44 IST FATAL:  connection to client lost
2016-12-19 12:25:45 IST ERROR:  deadlock detected
2016-12-19 12:25:45 IST DETAIL:  Process 8524 waits for ShareLock on transaction 84942; blocked by process 12520.
    Process 12520 waits for ShareLock on transaction 84940; blocked by process 20892.
    Process 20892 waits for ExclusiveLock on tuple (1,5) of relation 25911 of database 24736; blocked by process 8524.
    Process 8524: UPDATE TableA SET column1=column1- WHERE column2= and column3=
    Process 12520: UPDATE TableA SET column1=column1- WHERE column2= and column3=
    Process 20892: UPDATE TableA SET column1=column1- WHERE column2= and column3=
2016-12-19 12:25:45 IST HINT:  See server log for query details.
2016-12-19 12:25:45 IST CONTEXT:  while locking tuple (1,12) in relation "TableA"
2016-12-19 12:25:45 IST STATEMENT:  UPDATE TableA SET column1=column1- WHERE column2= and column3=
2016-12-19 12:25:45 IST LOG:  could not send data to client: No connection could be made because the target machine actively refused it.

在此多线程环境中,我希望 TableA 的行为 2 个语句锁定并避免死锁。

我看到类似的场景在 Postgres Docs

我找不到任何方法来避免这种死锁。任何帮助表示赞赏。谢谢

P.S:自动提交已设置为 FALSE,并尝试将 preparedStatements 与单个 UPDATE 查询一起使用。

关于多个查询 -> Multiple queries in one Preparedstatement and this 表明 postgres 不需要任何额外的配置。

根据我的经验,当您 "cross" 在 2 个长 运行 事务中更新时,PostgreSQL 中的死锁很可能发生在 "real life" 中。 (解释如下)。而且甚至很难在 PG 上模拟死锁。这是一个例子 - http://postgresql.freeideas.cz/simulate-deadlock-postgresql/ 所以经典死锁意味着:

  • 您开始事务 1 + 在第 1 行进行更新。您的过程继续,但事务 1 仍处于打开状态且未提交。
  • 然后开始事务 2 + 在第 2 行进行更新。过程继续但事务 2 仍处于打开状态且未提交。
  • 现在您尝试从导致此操作等待的事务 1 更新第 2 行。
  • 现在您尝试从事务 2 更新第 1 行 - 此时 PG 报告死锁并结束此事务。

所以我建议您尽快提交交易。

正如@Nick Barnes 在我分享的 link 评论中引用的那样。

The best defense against deadlocks is generally to avoid them by being certain that all applications using a database acquire locks on multiple objects in a consistent order.

特别是提到的更新死锁,更新的顺序导致死锁。

示例

UPDATE Table SET ... WHERE id= 1;
UPDATE Table SET ... WHERE id= 2;

UPDATE Table SET ... WHERE id= 2;
UPDATE Table SET ... WHERE id= 1;

一般的解决方案是根据 ID 对更新进行排序。这就是一致顺序的意思。

直到我与这个僵局作斗争,我才明白这一点。