不知何故,我总是在星期五得到这些。
我之前的问题是关于同样的问题,但我现在可以稍微缩小一点:
我整天都在玩这个,试图理解它。我有一个带有lock_version列的表,由此指定:
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
......没有任何反应。事实证明,我唯一一次得到正确(抛出异常)行为是第一次和第二次的lock_version为0.然而,在第一次保存之后,它再次为0。究竟是什么呢?
我正在使用ruby 1.8.6和活动记录2.2.2
...谢谢
答案 0 :(得分:6)
当你第一次调用some.sat第二次时,some_attribute_field的值已经等于“first”,activerecord知道这一点,所以它不会在db中更新到lock_version不会增加。第二次保存工作,因为db从未使用“first”更改。
尝试将第二个测试中的值更改为“first”以外的值,以使其与db中的值不同。
答案 1 :(得分:2)
我不是Ruby人,但乐观锁定对我来说很熟悉,所以我会尽力帮你调试它。
我认为第二次保存实际上更新了数据库。如果两个对象具有不同的lock_version并且在UPDATE中使用了lock_version,则根本不可能(UPDATE将更新零行)。所以,我们只有两种选择:
(实际上,还有第三种选择:save()都在他们自己的事务中,但我觉得你有AUTOCOMMIT = true )
你能看到实际的SQL语句吗? update语句应该是类似
的内容... WHERE JOB_ID=123 AND LOCK_VERSION=8
如果你手头有实际的查询,那么了解正在发生的事情会更加容易。
P.S。还有一个:在你的另一个主题的例子中,你有这个对象:
#<Job id: 323, lock: 8, worker_host: "second">
如果与加载时间相比未更改属性,则容器可以忽略save()调用。我不知道ActiveRecord是否有这种优化。但如果确实如此,则忽略第二个save(),并且乐观锁定没有机会启动。
答案 2 :(得分:1)
正如弗拉基米尔所说,你的测试/示例代码有点缺陷。在第二次保存期间,首先不会存储在日期库中!()因为没有更改属性。请参阅以下示例:
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中的示例,当第二个被保存时(两次都是!),它应该与Stale对象异常一起工作。