ActiveRecord中的关联并发

时间:2012-10-12 15:59:21

标签: ruby activerecord concurrency

我有一个人们注册商品的应用。每个项目的插槽数量有限。我该如何处理并发?我在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

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

这将更新零个或多个注册记录,因此您必须在提交事务之前检查是否保留了正确的计数。