我有一个人们注册商品的应用。每个项目的插槽数量有限。我该如何处理并发?我在Item类中尝试过这样:
def sign_up(signup)
ActiveRecord::Base.transaction do
return 'Sorry, that item is full.' if full?
signups << signup
sheet.save!
nil
end
end
def full?
locked_signups = signups.lock(true).all
locked_signups.size >= max_signups
end
我想通过AR尝试做什么?我是否需要通过列实现自己的锁定?欢迎任何建议。
更新:根据tadman的回答,我得到了这个工作。这是有效的代码:
rows_updated = ActiveRecord::Base.transaction do
Item.connection.update "update items set signup_count=signup_count+1 where id=#{ActiveRecord::Base.sanitize(self.id)} and signup_count<quantity"
end
return 'Sorry, that item is full. Refresh the page to see what\'s still open.' if rows_updated < 1
答案 0 :(得分:1)
我可以想到两种可靠的问题。
计数器列
您将创建剩余股票&#34;列并以原子方式更新它:
UPDATE sheet SET signups_remaining=signups_remaining-:count WHERE id=:id AND signups_remaining>=:count
您必须相应地绑定:count
和:id
值。如果此查询运行,则表示还有足够数量的注册。
保留注册
提前创建注册记录并分配它们:
UPDATE signups SET allocation_id=:allocation_id WHERE allocation_id IS NULL LIMIT :count
这将更新零个或多个注册记录,因此您必须在提交事务之前检查是否保留了正确的计数。