为什么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_版本或使用不正确
- 两个对象以某种方式获得了相同的锁定版本
... 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)。它什么都没做,因为没什么可做的。