Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/ruby-on-rails/66.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/ruby/20.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ruby on rails Rails应用程序中的模型实例在';你在接受检查吗?_Ruby On Rails_Ruby_Activerecord_Heroku_Heroku Postgres - Fatal编程技术网

Ruby on rails Rails应用程序中的模型实例在';你在接受检查吗?

Ruby on rails Rails应用程序中的模型实例在';你在接受检查吗?,ruby-on-rails,ruby,activerecord,heroku,heroku-postgres,Ruby On Rails,Ruby,Activerecord,Heroku,Heroku Postgres,我正在深入研究Rails4,我试图理解如何在多个DB连接访问模型数据时安全地访问模型数据。我有一些匹配逻辑,可以在队列中找到最老的用户,从队列中删除该用户,然后返回该用户 # UserQueue.rb class UserQueue < ActiveRecord::Base has_many :users def match_user(user) match = nil if self.users.count > 0 oldest = self.

我正在深入研究Rails4,我试图理解如何在多个DB连接访问模型数据时安全地访问模型数据。我有一些匹配逻辑,可以在队列中找到最老的用户,从队列中删除该用户,然后返回该用户

# UserQueue.rb
class UserQueue < ActiveRecord::Base
  has_many :users

  def match_user(user)
    match = nil
    if self.users.count > 0
      oldest = self.users.oldest_in_queue 
      if oldest.id != user.id
        self.users.delete(oldest)
        match = oldest
      end
    end
  end
end
#UserQueue.rb
类UserQueue0
最早=self.users.oldest\u在队列中
如果最旧的.id!=用户id
self.users.delete(最早的)
匹配=最老的
结束
结束
结束
结束
如果两个不同的线程同时执行此
match\u user
方法,它们是否都可以找到相同的
最老的
用户并尝试将其从队列中删除,然后将其返回给调用者?如果是这样,我如何防止这种情况

我研究了事务,但它们似乎不是一个解决方案,因为在本例中只有一个模型被修改(队列)


提前感谢您的智慧

是的,这绝对有可能发生。如何防止它取决于应用程序/框架/数据库等的其余部分

事务不会有帮助,因为两个客户端可以同时启动请求,并且都会看到与最早的相同的UserQueue记录

你想要一个。但是,如果有其他方法修改数据(如直接通过SQL等),代码中的互斥并不理想。它也会变得混乱,因为当您第一次忘记使用互斥时,您已经打开了竞争条件。再说一次,也许这已经足够了。请记住,互斥体需要跨线程和进程等工作

您可能会看到数据库是否有互斥锁或其他行级锁,您可以使用它们来标记最早的队列记录,然后将其提取出来

或者找到另一种方法来获取最早的队列,从而完全避免竞争条件。比如:

  • SQL更新id不是user.id的最旧队列,并将“标记的\u用于\u工作”设置为某个唯一id
  • 获取其标记的工作值为唯一ID的队列行

由于SQL更新是原子的(当然,它应该是!),因此您可以使用上面的代码运行多个线程而不必担心。

ActiveRecord支持行锁定

这是取自:

11.1乐观锁定

乐观锁定允许多个用户访问同一记录进行编辑,并假设与数据的冲突最小。它通过检查另一个进程是否在记录打开后对其进行了更改来实现这一点。如果发生异常并且忽略更新,则会引发
ActiveRecord::StaleObjectError
异常

乐观锁定列

为了使用乐观锁定,表需要有一个名为
lock\u version
的整型列。每次更新记录时,活动记录都会增加
lock\u version
列。如果更新请求在
lock\u version
字段中的值低于数据库中当前
lock\u version
列中的值,则更新请求将失败,并出现
ActiveRecord::StaleObjectError
。例如:

然后,您负责处理冲突,方法是拯救异常并回滚、合并或以其他方式应用解决冲突所需的业务逻辑

通过设置
ActiveRecord::Base.lock\u optimically=false
,可以关闭此行为

要覆盖
lock\u version
列的名称,
ActiveRecord::Base
提供了一个名为
locking\u列的类属性

class客户端

我建议你读一读。

谢谢你,很好。如果我理解正确,听起来我只需要将代码包装在begin/rescue块中,并添加处理队列第二次修改情况所需的业务逻辑?另外,在阅读了指南之后,看起来我也可以使用“悲观”锁定,只需将代码包装在事务中并调用lock!关于self(队列实例)?再次感谢!
c1 = Client.find(1)
c2 = Client.find(1)

c1.first_name = "Michael"
c1.save

c2.name = "should fail"
c2.save # Raises an ActiveRecord::StaleObjectError
class Client < ActiveRecord::Base
  self.locking_column = :lock_client_column
end