rails - 实现一个简单的锁,以防止用户同时编辑相同的数据

时间:2009-11-26 13:06:34

标签: ruby-on-rails concurrency locking mutex

我有一个应用程序,我需要阻止用户在由其他用户编辑数据时编辑数据。我正在考虑最好的方法,并想要提出想法。到目前为止,我已经创建了一个设置模型,可以在键/值对中存储db上的应用程序范围配置。因此,对于锁,我有一个名为LOCKED_TABLE_UID的设置实例,它存储了编辑表的用户的user_id,如果表是空闲的,则为null(nil)。

>> lock = Setting.find_by_key('LOCKED_TABLE_UID')

然后,我在应用程序控制器中实现了2个方法来获取和释放锁:

# current_user returns the user currently logged in
def acquire_lock
  lock = Setting.find_by_key("LOCKED_TABLE_UID")
  if lock.value
    # if lock taken, see if it's the current_user or someone else
    if lock.value.to_i == current_user.id.to_i
      return true
    else
      return false
    end
  else
    # lock is free, assign it to this user
    lock.value = current_user.id
    return true if lock.save
  end
end

def release_lock
  lock = Setting.find_by_key("LOCKED_TABLE_UID")
  if lock.value
    # the lock belongs to current_user, so he can release it
    if lock.value.to_i == current_user.id.to_i
      lock.value = nil
      return true if lock.save
    else
      # not your lock, go away
      return false
    end
  else
    # lock is free, quit bugging
    return true
  end
end

我想要的是创建一些包含锁定机制的块代码,如下所示:

def some_crud_action
  requires_locking do |lock|
    if lock
      # do some CRUD stuff here
    else
      # decline CRUD and give some error
    end
  end
end

我很欣赏这方面的帮助 - 但我也对其他如何完成所有这些或者我可能忽略的事情持开放态度。这个锁不一定是原子的,但是相当基本也是最重要的 - 它有效:) 感谢。

4 个答案:

答案 0 :(得分:7)

您是否看过ActiveRecord内置锁定功能?

答案 1 :(得分:1)

你快到了。创建require_locking?你认为合适的行动。然后使用before_filter处理它。

 before_filter :requires_locking?, :only => [:update, :destroy]
 after_filter :release_lock, :only => [:update, :destroy]

 def requires_locking do |lock|
   unless acquire_lock
      lock = Setting.find_by_key("LOCKED_TABLE_UID")
      user_with_lock = User.find(lock.value)
      flash[:message] = "Action denied: Table locked by: #{user_with_lock.name}"
      redirect_to :back
   end
 end

答案 2 :(得分:0)

我喜欢这个想法,但看到你的解决方案存在一个大问题,那就是你正在获取并释放整个表的锁。

对于一个可能很好的非常小的应用程序,但想象一下,如果有成千上万的用户试图访问,例如,“产品”表,并且必须等待,因为有人正在编辑与他们自己的产品完全无关的条目。

也许你可以采用更细粒度的方法来锁定特定的行而不是表格。然后锁将包括表名,行ID和用户ID。

答案 3 :(得分:0)

我认为acts_as_lockable_by gem确实可以用更简单的术语和更少的代码来完成您所要求的工作。它可以很容易地与Rails甚至是裸露的ruby项目集成。

有了这个gem,您将获得原子lockunlockrenew_lock方法。另外,您会获得ttl自动失效的锁,因此,如果狗屎撞到了风扇并且您无法解锁资源,它将自动为您解锁!