最近,我们遇到了死锁问题。我们系统的两个部分将在相似的时间内更新同一个表,一个更新(名称为“UP1”)一个事务中的几行,另一个(命名为“UP2”)使用像“update ... where id”这样的sql在(...)“。
看起来好像是因为那个,sql中的id“update ... where in(...)”是乱序的,例如。 “5,6,2,3,4,1”;在交易中,更新操作将按此顺序“1,2,3,4,5,6”执行。当“UP1”更新id“1,2,3,4”和“UP2”更新id“5,6”时,“UP1”想要被“UP2”锁定的id 5和“UP2”想要被“UP1”锁定的id 2,所以死锁就出来了。
我的问题是,db锁行是一个接一个,只在sql或事务完成后释放它们?如果没有,为什么不能在事务开始时锁定所有行或“在(...)sql中的id”,为什么不能逐个释放更新的行?
期待任何有用的回复,thx。
答案 0 :(得分:1)
你几乎走在正确的轨道上。使用默认的Read Committed Isolation Level PostgreSQL沿途获取锁定,并在提交或回滚事务时释放它们。
如果您可以确保所有UPDATE操作以相同的顺序更新行,您将永远不会遇到死锁。您是否尝试按升序更新UP1
行,并以同样的方式对IN
UP2
列表进行排序?
如果您无法保证同步更新,则可能对Serializable Isolation Level感兴趣。它是最严格的隔离级别,可能会减慢您的查询速度,特别是在重度并发时。但它应该可以防止你看到的错误。此外,准备好因序列化失败而重试事务。
为此,start your transaction使用:
BEGIN ISOLATION LEVEL SERIALIZABLE;