上下文:产品正在由多个线程更新。因此,它引领了比赛条件。所以我使用乐观锁定,因为它经常不更新。产品的最新更新状态由updated_at
属性确定。
例如,在机器上的t1上更新Prod(id = 1):1。机器2上的t2处更新了相同的产品(id = 1)。现在,机器:1上Prod(id = 1)的状态已过时。
方法要确定陈旧:我将比较计算机上updated_at
的值与数据库值中updated_at
的存储值。
我主要关心的是设置@original_updated_at
的值。我应该使用attr_writer :original_updated_at
吗?这是乐观锁定的正确方法。
attr_accessor : :original_updated_at
def original_updated_at
@original_updated_at || updated_at.to_f
end
def stale_object?
if updated_at.to_f > original_updated_at.to_f
@original_updated_at = nil
return true
else
@original_updated_at = updated_at.to_f
return false
end
end
def recalculate
tries = 0
begin
raise Product::StaleObjectError.new("StaleObjectError") if stale_object?
attributes["updated_at"] = Time.now.utc
Product.where(:id => self.id).update_all(attributes)
self.attributes = attributes
rescue Product::StaleObjectError => e
if tries < MAX_RETRIES
tries += 1
sleep(1 + tries)
reload
retry
else
raise Product::StaleObjectError("StaleObjectError")
end
end
end
答案 0 :(得分:0)
您似乎正在使用Rails?不知道为什么要尝试推出自己的解决方案。
只需添加一个lock_version
列即可在数据库级别启用乐观锁定。
https://api.rubyonrails.org/classes/ActiveRecord/Locking/Optimistic.html
另外:由于您在谈论多台计算机,因此并发可能来自多个进程和多个线程。
由于您的旧系统在添加锁列时中断,因此需要采取其他解决方案:
0)解决乐观锁定问题
1)使用悲观锁定。根据负载情况-多少个并发读/写-该操作也可能会起作用
2)修正您的锁定代码(由于您将保留有关该类的一些细节,因此无法完全确定其工作原理)
break
即可)to_f
self.attributes = attributes
应该做什么(根据您显示的代码,我们不清楚attributes
是否不是self.attributes
之外的东西)sleep
是一种代码味道当编写的代码太复杂以至于不得不在互联网上询问它是否有效时,那么您可能走错了路。使用乐观锁定解决问题,而不要添加这种解决方法。