获取过期对象错误。乐观锁:它是如何工作的?

7

我认为我已经清除了所有问题,但是我不确定我是否完全理解OL。一般来说,假设你和我在一个团队中来保持foo的最新状态。我在一个房间里,决定节省时间,自己更新foo。一分钟后,你也有了同样的想法,并登录到编辑页面以更新它。如果我先完成会发生什么?如果你先完成会发生什么?在配置失败的情况下,它如何区分某人是否正在编辑或阅读。如果我使用catch并重新加载以更新锁,则会丢失所有更改,如何解决这个问题?在这里,重新执行更新非常简单,但可能是更复杂表单对象的一部分。

我的具体问题出现在我加载了一个副本到浏览器中(据我所知是最好的),然后忘记了它,然后在我的控制台中加载了另一个副本(锁:0?),无法用陈旧的对象错误更新我的控制台中的副本。注意到浏览器上的内容。关闭了我的控制台。尝试重新加载我的浏览器,结果也得到了陈旧的对象错误。这是代码失败的地方:

=>  7:       self.update_attributes({
    8:         failed_view_attempts: self.failed_view_attempts += 1,
    9:         failed_view_at: Time.now
   10:       })
   11:     end
(byebug) self
#<Product id: 12... lock_version: 0>

#=> ActiveRecord::StaleObjectError (Attempted to update a stale object: Product.)

我尝试过的事情:

为了查看是否加载了另一个实例,我在after_initialize回调中添加了puts "CALLED !!!!",但它只打印了一次。

在从错误中恢复并返回self.changed后检查,得到了["updated_at", "failed_view_attempts", "failed_view_at"]

2个回答

4

需要将lock_version列的默认值设置为零(0)。


2

乐观锁定基于对象版本号。

读取对象不应该对版本号产生任何影响。

如果您尝试更新某个对象,则会比较此版本号(实际上在 SQL 中使用更新语句,例如“update ... where version = 1 and ...”),并在更新时增加此版本号。

如果在尝试更新时比较失败,则会出现过期对象错误。这意味着在您进行更改时,其他人修改了该对象。

要解决此错误,您需要重新加载对象以获取实际版本,并可能手动合并更改(向用户提供一些信息,让用户自行决定)。


但是,如果我正在编辑时有人调用同一行的实例来读取它,它将会使版本号增加。这基于加载它,而不是你对它所做的操作,是吗? - MCB
如果你不加载它,版本号就不会改变,否则会有很多更新,所以版本号只在更新时增加(例如:更新版本=2,其中版本=1),如果没有记录与where匹配,则会出现旧对象错误。页面重新加载的问题可能是缓存了,你没有从数据库重新加载对象。 - Martin Kukan
是的,浏览器使用缓存版本是我已经熟悉的。 - MCB

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接