2

我有以下关系

parent has_many children 
child  belongs_to parent

和下面的代码块

ActiveRecord::Base.connection.transaction do
  lock_acquired = true
  if child.parent.lock! and child.parent.status == 1
    child.parent.update_attributes(:status => 2)
  else
    lock_acquired = false
  end

  if lock_acquired
   # other code follows here
  end

end

上面的代码块是为了确保一次只有一个孩子能够改变父母状态,从而锁定!方法和状态检查表达式。但不知何故它坏了。即使其中一个孩子将父状态更改为 2,另一个孩子也能以某种方式通过 if 语句。当然有多个进程正在运行,但我认为 lock 会解决这个问题。看起来像在事务块完成之前返回锁。

可能是锁的工作方式与我预期的不同。任何见解都会非常有帮助。

谢谢。

4

1 回答 1

1

我不太确定为什么您更新的代码不起作用,但有一件奇怪的事情:您使用lock!的好像它返回一个真/假值,但它只能返回模型实例本身(如果锁被获取)或引发错误(如果获取锁超时)。这意味着lock_acquired只有在实际false获得了锁,但父级的状态不等于 时才会设置为。1

此代码的行为可能更具可预测性:

child.parent.with_lock do
  if child.parent.status == 1
    child.parent.update_attributes(:status => 2)
  end

  # other code follows here
end

请注意,with_lock其行为类似于lock!-- 要么将执行块,要么将引发锁定超时错误(在默认 MySQL 设置下等待 50 秒后)。

于 2013-08-20T19:27:53.273 回答