我的Postgres表:
表演
性能
基
我经常需要从一个组中选择所有表演者并更新他们的所有队伍。但这通常会导致死锁,因为我正在进行SELECT ... FOR UPDATE
选择,而其他线程同时INSERT
。
我看到很多错误的例子(在Python SqlAlchemy中):
DBAPIError: (TransactionRollbackError) deadlock detected
DETAIL: Process 83182 waits for ShareLock on transaction 14282922; blocked by process 83171.
Process 83171 waits for ShareLock on transaction 14282925; blocked by process 83182.
HINT: See server log for query details.
'SELECT performers.id AS performers_id, performers.rank AS performers_rank, performers.group_id AS performers_group_id \nFROM performers \nWHERE performers.group_id = %(group_id_1)s FOR UPDATE' {'group_id_1': 2}
我found周围examples也有behavior个。{/ p>
我该如何解决这个问题?我可以切换到不同的事务锁定级别吗?我宁愿不只是中止而且必须重试 - 我希望数据库能够为我解决这个问题。
必须有某种方法来解决这个问题 - 我想做的事情非常简单。
答案 0 :(得分:2)
如果所有并发写入操作都以相同的唯一顺序进行,则可以避免死锁。将ORDER BY
添加到锁定语句中,并在所有位置使用相同的排序顺序。类似的东西:
SELECT ... FROM performers WHERE ... ORDER BY performers.id FOR UPDATE
id
将成为主键(或任何其他稳定,明确的列组合)。
此外,如果您的操作涉及多个列,请在表中严格按照相同的顺序进行锁定。
this thread in pgsql-general list中的更多详情 Or in the manual
将触发器(和外键约束)保持在必要的最小值。无论哪种方式,首先要排序FOR UPDATE
锁。这可能只是解决你的问题。如果没有,请考虑不同的transaction isolation level。 Serializable应该做到这一点。但是,必须准备好重试交易,直到它们成功为止。