如何避免更新死锁
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 对更新进行排序。这就是一致顺序的意思。
直到我与这个僵局作斗争,我才明白这一点。
在使用 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 对更新进行排序。这就是一致顺序的意思。
直到我与这个僵局作斗争,我才明白这一点。