如何避免更新死锁

时间:2016-12-19 09:08:36

标签: multithreading postgresql jdbc sql-update deadlock

使用Postgres处理JDBC时...

Isolationlevel =" Read committed"

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

  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+$1 WHERE column2=$2 and column3=$3
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-$1 WHERE column2=$2 and column3=$3
    Process 12520: UPDATE TableA SET column1=column1-$1 WHERE column2=$2 and column3=$3
    Process 20892: UPDATE TableA SET column1=column1-$1 WHERE column2=$2 and column3=$3
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-$1 WHERE column2=$2 and column3=$3
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:Autocommit已经设置为FALSE并尝试使用带有单个UPDATE查询的preparedStatements。

关于多个查询 - > Multiple queries in one Preparedstatementthis表明postgres不需要任何其他配置。

2 个答案:

答案 0 :(得分:7)

@Nick Barnes在评论中引用了我分享的链接。

  

防止死锁的最佳方法通常是避免死亡   确定使用数据库的所有应用程序都获得锁定   多个对象采用一致的顺序

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

示例

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 订购更新。这就是一致的顺序意味着什么。

我一直都不明白,直到我为这个僵局而斗争。

答案 1 :(得分:2)

根据我的经验,PostgreSQL中的死锁最有可能发生在"现实生活中#34;当你"交叉"更新2个长时间运行的事务。 (解释如下)。甚至很难模拟PG上的死锁。这是一个例子 - http://postgresql.freeideas.cz/simulate-deadlock-postgresql/ 所以经典的死锁意味着:

  • 您启动事务1 +在第1行执行更新。您的过程仍在继续,但事务1仍然打开但未提交。
  • 然后启动事务2 +在第2行执行更新。过程继续,但事务2仍然打开但未提交。
  • 现在您尝试更新事务1中的第2行,这会导致此操作等待。
  • 现在您尝试从事务2更新第1行 - 此时PG报告死锁并结束此事务。

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