Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/symfony/6.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
为什么activerecord乐观锁定每行只工作一次?_Activerecord_Locking_Optimistic Locking_Optimistic - Fatal编程技术网

为什么activerecord乐观锁定每行只工作一次?

为什么activerecord乐观锁定每行只工作一次?,activerecord,locking,optimistic-locking,optimistic,Activerecord,Locking,Optimistic Locking,Optimistic,不知怎么的,我总是在星期五买这些 我之前的问题是关于同一个问题,但我现在可以缩小范围: 我整天都在玩这个,想弄明白它的意思。我有一个带有锁型柱的表,指定如下: add_column :jobs, :lock_version, :integer, :default=>0 我会这样做: foo = job.create! first = Job.find(foo.id) second = Job.find(foo.id) 然后,我验证第一个和第二个引用了相同的对象——它们的ID是相同的,并

不知怎么的,我总是在星期五买这些

我之前的问题是关于同一个问题,但我现在可以缩小范围:

我整天都在玩这个,想弄明白它的意思。我有一个带有锁型柱的表,指定如下:

add_column :jobs, :lock_version, :integer, :default=>0
我会这样做:

foo = job.create!
first = Job.find(foo.id)
second = Job.find(foo.id)
然后,我验证第一个和第二个引用了相同的对象——它们的ID是相同的,并且我使用mysql命令行工具在数据库中看到了该行

first.some_attribute_field = 'first'
second.some_attribute_field = 'second'
first.save
second.save
到目前为止没有问题。我正确地获得了ActiveRecord::StaleObjectError异常但是

first = Job.find(foo.id)
second = Job.find(foo.id)
first.some_attribute_field = 'first'
second.some_attribute_field = 'second'
first.save
second.save
…什么也没发生。事实证明,我唯一得到正确(抛出异常)行为的时间是当第一个和第二个具有0的lock_版本时。但是,在第一次保存之后,它再也不会是0。这到底是怎么回事

我正在使用ruby 1.8.6和active record 2.2.2


谢谢…

我不是Ruby迷,但是乐观锁定对我来说很熟悉,所以我会尽力帮你调试它

我认为第二次保存实际上更新了数据库。如果两个对象都有不同的lock_版本,并且在更新中使用了lock_版本,那么这是不可能的(更新将更新零行)。因此,我们只有两种选择:

  • UPDATE语句中未使用lock_版本或使用不正确
  • 两个对象以某种方式获得了相同的锁定版本
(实际上,还有第三种选择:save()和save()都在各自的事务中,但我觉得您的AUTOCOMMIT=true)

您能使实际的SQL语句可见吗?update语句应该如下所示

... WHERE JOB_ID=123 AND LOCK_VERSION=8
当您手头有实际的查询时,理解正在发生的事情会容易得多

还有一点:在另一个主题的示例中,您有以下对象:

#<Job id: 323, lock: 8, worker_host: "second">
#

如果与加载时间相比属性没有更改,则容器可能会忽略save()调用。我不知道ActiveRecord是否有这种优化。但是如果是这样,那么第二个save()将被忽略,并且乐观锁定没有机会启动。

当您调用first.save第二次时,某些属性字段的值已经等于“first”,activerecord知道这一点,因此它不会在数据库中更新以锁定版本不会增加。第二次保存有效,因为数据库从未用“第一次”更改


尝试将第二个测试中的值更改为“第一个”以外的值,以便与db中的值不同。

正如Vladimir所说,您的测试/示例代码有点缺陷。在第二次保存期间,第一次不会存储在数据库中!(),因为没有更改任何属性。请参见以下示例:

foo = Account.create!

first = Account.find(foo.id)
first.cash = 100
first.save!


first = Account.find(foo.id)
first.cash = 100

puts "First lock before " + first.lock_version.to_s
first.save!
puts "First lock after " + first.lock_version.to_s
这将产生:

% script/runner another_tester.rb                               
First lock before 1
First lock after 1

在2.3.2版本的rails中使用您的示例,在保存第二个时(两次!)会出现过时的对象异常。我刚刚用2.2.2进行了相同的测试,结果正确(两次都出现过时的对象异常)。您可能希望在API中查找“脏”和“更改”(我使用的是gotapi.com)。它什么都没做,因为没什么可做的。