如何锁定兄弟姐妹以防止竞争情况

问题描述 投票:0回答:1

型号:

Class Checklist
  has_many :checklist_items
end
Class ChecklistItem
  belongs_to :checklist

  after_save :update_checklist_completion

  def update_checklist_completion
    if siblings.unchecked.any?
      checklist.update(completed: false)
    else
      checklist.update(completed: true)
    end
  end
end

保存清单项目后,它会运行

update_checklist_completion
- 如果清单上的所有其他清单项目也已完成,那么它将更新要完成的清单。问题是,如果清单项目完成得太快,那么当该方法在最后一个清单项目上运行时,之前的清单项目尚未完成更新,因此无法将清单项目标记为已完成。

我相信这是一个竞争条件。我的想法是,最好在执行

update_checklist_completion
时防止兄弟姐妹被更新,但不确定实现此目的的最佳方法。我看过
Mutex
但这似乎阻止了在该对象上访问该方法。就我而言,我认为我需要阻止其他对象(兄弟姐妹)更新

ruby-on-rails mutex race-condition
1个回答
0
投票

可能回调,尤其是非数据库回调不太适合此目的

如果需要,您可以锁定所有记录(父项和所有子项)。然后在打开的事务中保存子记录,检查其他子记录并更新父记录

类似这样的:

checklist.with_lock do
  checklist.checklist_items.lock!
  checklist_item.save!
  
  completed = !checklist.checklist_items.unchecked.exists?

  checklist.update!(completed:)
end

注意:如果在不同的地方应用不同的锁定顺序,就会出现死锁

© www.soinside.com 2019 - 2024. All rights reserved.