Rails 文档的悲观锁定示例中的竞争条件

问题描述 投票:0回答:1

我正在查看 Rails 文档的以下示例:

account = Account.first
account.with_lock do
  # This block is called within a transaction,
  # account is already locked.
  account.balance -= 100
  account.save!
end

我的理解是,

first
方法直接从数据库返回记录,而不是关系(类似于
find
)。现在假设
balance = 200
并且我们有两个并发请求,它们都在到达
account = Account.first
块之前执行
with_lock
。现在,这两个请求在内存中都有
200

然后,一个请求锁定记录并将

balance
修改为 100。但是当它解锁记录时,第二个请求不会再次读取
balance
,但它将具有
200
的旧值,因此我们将在这种情况下仍然会出现竞争条件。所以我的问题是,是否应该将
account = Account.first
也包裹在
with_lock
块中以真正避免竞争条件?

ruby-on-rails ruby race-condition
1个回答
0
投票

with_lock
在屈服于块之前重新加载对象,来自 docs:

将传递的块包装在事务中,在屈服之前用锁重新加载对象。

(几乎)相当于:

account = Account.first
account.transaction do
  account.reload(lock: true)
  account.balance -= 100
  account.save!
end

reload
调用确保对象的属性从数据库中得到更新。

© www.soinside.com 2019 - 2024. All rights reserved.