postgresql - 简单更新时的死锁:ShareLock 和 AccessExclusiveLock
问题描述
我注意到错误日志中偶尔会出现死锁,原因是同一行的并行更新:
[1111]:LOG: process 1111 detected deadlock while waiting for ShareLock on transaction 123456789 after 1000.095 ms
[1111]:DETAIL: Process holding the lock: 2222. Wait queue: .
[1111]:CONTEXT: while locking tuple (9999999,99) in relation "ccc"
[1111]:STATEMENT: update ccc set modification_date_time=$1, ... where id=$7
[1111]:ERROR: deadlock detected
[1111]:DETAIL: Process 1111 waits for ShareLock on transaction 123456789; blocked by process 2222.
Process 2222 waits for AccessExclusiveLock on tuple (9999999,99) of relation 55555 of database 66666; blocked by process 1111.
Process 1111: update ccc set modification_date_time=$1, ... where id=$7
Process 2222: update ccc set modification_date_time=$1, ... where id=$7
[1111]:HINT: See server log for query details.
应用程序中发生的情况如下:
- Hibernate 加载实体(行)
- 正在修改字段
- Hibernate将实体保存到数据库,产生
UPDATE
语句
目前尚不清楚为什么会发生这种情况,因为这只是一次正常的更新,进程不应相互依赖。我知道这是一个竞争条件,但从应用程序的角度来看,这并不重要。
我不完全理解,什么是ShareLock
and AccessExclusiveLock
,所以到目前为止我有两个想法:
- 当实体被修改时,Hibernate/DB 必须提高锁定级别,并且它失败了,因为其他线程已经对该行有一些锁定。解决方案 - 提前锁定?
- 有时事务太慢(> 1s),死锁会产生误报。解决方案 - 增加超时?
解决方案
发生死锁必须涉及多个锁定对象。
检查事务已更新了哪些其他行。如果您负担得起,也许您可以打开 SQL 日志记录。
死锁通常可以通过以某种特定顺序锁定行来避免,例如通过升序 ID。
缓慢的处理不会导致死锁,尽管长事务会增加危险。
如果死锁很少发生,不要担心它们。只需重试事务。
推荐阅读
- angular - 创建可重用的 HTTP 拦截器库 Angular
- javascript - 谷歌助手输入到 Python 输出
- swift - SpriteKit 非弹性碰撞降低速度
- xcode - 如何在 Visual Studio Mac 中使用旧版本的 Xamarin.iOS?
- arrays - 将元素添加到向量的前面,而不知道它是行向量还是列向量?
- c# - 值类型字符串不能用作默认参数
- xml - Delphi XML 订单
- python - 如何重新排列这个 pandas 数据框?
- neural-network - NOT 感知器的双重权重和偏差应该是多少?
- macos - 如何在 Apple Mac 上使用 tfs 源代码控制