简单更新期间的死锁:ShareLock和AccessExclusiveLock

时间:2018-06-08 10:02:46

标签: postgresql hibernate

我注意到错误日志中偶尔出现死锁,原因是同一行的并行更新:

[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.

申请中会发生以下情况:

  1. Hibernate加载实体(行)
  2. 正在修改字段
  3. Hibernate将实体保存到数据库,从而生成UPDATE语句
  4. 目前尚不清楚它为什么会发生,因为它只是一次正常的更新,而且流程不应该相互依赖。我知道这是一种竞争条件,但从应用的角度来看,它并不重要。

    我不完全明白,ShareLockAccessExclusiveLock是什么,所以到目前为止我有2个想法:

    • 当实体被修改时,Hibernate / DB必须提高锁级别,并且它失败,因为其他线程已经对此行有一些锁定。解决方案 - 早期锁定?
    • 有时交易太慢(> 1s),死锁会产生误报。解决方案 - 增加超时?

1 个答案:

答案 0 :(得分:1)

必须有多个锁定对象才能发生死锁。

检查事务已更新的其他行。如果你负担得起,也许你可以打开SQL日志。

通过按特定顺序锁定行,通常可以避免死锁,例如通过升序ID。

虽然长时间的交易增加了危险,但是处理速度慢不会造成死锁。

如果僵局很少发生,请不要担心它们。只需重试交易即可。