You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Ruby on Rails批量更新PostgreSQL记录触发死锁问题求助

原因分析
  • 生产环境并发冲突:本地无并发请求,生产环境却可能存在多个事务同时操作这批用户记录(比如其他请求也在更新同批用户、或修改关联表数据),当不同事务更新行的顺序不一致时,就会出现循环等待锁的死锁场景。
  • 行锁顺序不一致:update_all默认按数据库返回的行顺序更新,不同事务可能拿到不同的行顺序——比如事务A先更用户ID 100再更ID 50,事务B先更ID 50再更ID 100,两者会互相等待对方释放锁,触发死锁。
  • 事务范围差异:生产环境中这个更新操作可能处于更大的事务上下文里,锁持有时间更长,增加了和其他事务冲突的概率;而本地测试的事务范围更小,冲突概率极低。
解决方案
  • 固定更新顺序:强制按统一顺序(比如ID升序)更新记录,确保所有事务更新行的顺序一致,从根源避免循环等待。修改代码为:
    company.users.order(:id).update_all(company_name: company.name)
    
  • 拆分批量更新:将800条记录拆分成多个小批次更新,缩短单次锁的持有时间,降低冲突概率。示例代码:
    company.users.find_in_batches(batch_size: 100) do |batch|
      batch.update_all(company_name: company.name)
    end
    
  • 缩小事务范围:检查代码是否将更新操作放在了不必要的大事务中,尽量让更新操作单独提交,减少锁的持有时长。
  • 排查并发操作:生产环境可通过查询PostgreSQL的pg_locks视图,确认是否有其他事务在同时操作这批用户记录,针对性优化那些并发操作的锁顺序。

内容的提问来源于stack exchange,提问作者Asad Shahid

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.26 00:47:09