0

我有一个应用程序,人们可以在其中注册项目。每个项目都有有限数量的插槽。如何处理并发?我在 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
4

1 回答 1

1

我可以想到两种可靠的解决此类问题的方法。

计数器列

您将创建一个“剩余库存”列并自动更新它:

UPDATE sheet SET signups_remaining=signups_remaining-:count WHERE id=:id AND signups_remaining>=:count

您必须相应地绑定到:countand:id值。如果此查询运行,则意味着还有足够数量的注册。

保留注册

预先创建注册记录并分配它们:

UPDATE signups SET allocation_id=:allocation_id WHERE allocation_id IS NULL LIMIT :count

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

于 2012-10-12T17:00:45.170 回答