我的 Postgres 表:
表演者
表演
团体
我经常需要从一个组中选择所有的表演者并更新他们的所有排名。但这通常会导致死锁,因为我正在执行
SELECT ... FOR UPDATE
select 并且其他线程同时执行 INSERT
ing。我经常看到的错误示例(在 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 。
我怎样才能解决这个问题?我可以切换到不同的事务锁定级别吗?我宁愿不只是中止而不得不重试 - 我希望数据库为我处理这个争用。
一定有办法解决这个问题——我想做的很简单。
最佳答案
如果所有并发写操作都以 相同的唯一顺序 进行,则可以避免死锁。将 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 应该可以解决问题。但是,您必须准备好重试事务,直到它们成功为止。关于python - postgres 使用 UPDATE FOR 和外键锁定,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/22308990/