如何为操作锁定一组对象?

Joh*_*hir 5 activerecord locking transactions ruby-on-rails

在我的rails应用程序中,我有一些这样的代码:

def foo
  if object_bar_exists
    raise "can't create bar twice!"
  end

  Bar.create
end
Run Code Online (Sandbox Code Playgroud)

这可以通过进入应用程序服务器的两个不同请求来调用.如果此代码同时由两个请求运行,并且它们同时运行if检查,则不会找到另一个bar,并且bar将创建2 秒.

为"酒吧集合"创建"互斥体"的最佳方法是什么?DB中的专用互斥表?

更新

我应该强调,我不能在这里使用内存互斥,因为并发是跨请求/进程而不是线程.

Pan*_*kos 6

最好的办法是在数据库事务中执行操作.因为您最终可能会运行多个应用程序并且它们很可能不会共享内存,所以您将无法在应用程序级别创建Mutex锁定,尤其是当这两个应用程序服务在完全不同的物理机箱上运行时.以下是如何完成数据库事务:

ActiveRecord::Base.transaction do
  # Transaction code goes here.
end
Run Code Online (Sandbox Code Playgroud)

如果要确保在数据库事务上回滚,则必须在Bar类上启用验证,以便无效的保存请求将导致回滚:

ActiveRecord::Base.transaction do
  bar = Bar.new(params[:bar])
  bar.save!
end
Run Code Online (Sandbox Code Playgroud)

如果数据库中已经有一个bar对象,则可以像这样悲观地锁定该对象:

ActiveRecord::Base.transaction do
  bar = Bar.find(1, :lock => true)
  # perform operations on bar
end
Run Code Online (Sandbox Code Playgroud)

  • 您真的希望事务**和**是数据库中的唯一索引来强制解决问题.当出现问题时,事务将保持一切清洁,唯一索引会在出现问题时告诉您. (2认同)