【问题标题】:Rails 3 - Potential Race Condition?Rails 3 - 潜在的竞争条件?
【发布时间】:2011-07-20 21:13:41
【问题描述】:

我有一个非常简单的 Rails 3 应用程序,用户可以在其中为特定日期保留有限数量的同类项目中的一个。我试图避免两个人在特定日期保留最后一个可用项目的竞争条件。模型(简化)如下:

class Reservation < ActiveRecord::Base
  belongs_to :user
  attr_accessible :date
  MAX_THINGS_AVAILABLE = 20

  validate :check_things_available

  def check_things_available
    unless things_available? errors[:base] << "No things available"
  end

  def things_available?
    Reservation.find_all_by_date(date).count < MAX_THINGS_AVAILABLE 
  end           
end

正在通过current_user.reservations.build(params[:reservation])在控制器中创建预留

感觉有更好的方法可以做到这一点,但我不能完全确定它是什么。任何有关如何防止竞争条件的帮助将不胜感激。

【问题讨论】:

  • 您提供的链接引用了更新现有记录中的属性/列,当创建两个新记录时会出现我的竞争条件。我错过了什么吗?另外,我不清楚在这种情况下行级锁定是否有效,因为我使用的是从所有行的子集派生的计数。
  • 我认为使用前置过滤器是最简单的方法。如果它们返回 false,则整个事务被取消。

标签: ruby-on-rails ruby-on-rails-3 activerecord


【解决方案1】:

不确定这是否能回答您的问题,但它可能会为您指明解决方案:

http://webcache.googleusercontent.com/search?q=cache:http://barelyenough.org/blog/2007/11/activerecord-race-conditions/

(原来的网站好像挂了,所以这是一个到谷歌缓存的链接)

该页面上的结论是乐观锁定和行级锁定不是创建时竞争条件的解决方案,只是在更新时。

作者建议使用 db 约束重新实现 find_or_create。

另一个建议是将事务隔离级别切换为“可序列化”应该可以工作,但没有关于如何在 Rails 中执行此操作的信息。

【讨论】:

    【解决方案2】:

    只需使用任何锁定机制,例如redis locker

    RedisLocker.new("thing_to_sell_#{@thing.id}").run do
      current_user.create_reservation(@thing) or raise "Item already sold to another user"
    end
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-05-31
      • 1970-01-01
      相关资源
      最近更新 更多