我的 Postgres 表:

表演者

  • id
  • 排名
  • group_id 引用组

  • 表演
  • id
  • 支付
  • performer_id 引用表演者

  • 团体
  • id

  • 我经常需要从一个组中选择所有的表演者并更新他们的所有排名。但这通常会导致死锁,因为我正在执行 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 levelSerializable 应该可以解决问题。但是,您必须准备好重试事务,直到它们成功为止。

    关于python - postgres 使用 UPDATE FOR 和外键锁定,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/22308990/

    10-12 02:47
    查看更多