这是我的类:
class Plan < ActiveRecord::Base
def testing
self.with_lock do
update_columns(lock: true)
byebug
end
end
def testing2
self.lock!
byebug
end
end
我打开了两个导轨控制台。
在第一个控制台中:
p = Plan.create
=> (basically success)
p.id
=> 12
p.testing2
(byebug) # simulation of halting the execution,
(BYEBUG) # I just leave the rails console open and wait at here. I expect others won't be able to update p because I still got the lock.
在第二个控制台上:
p = Plan.find(12)
=> (basically said found)
p.name = 'should not be able to be stored in database'
=> "should not be able to be stored in database"
p.save!
=> true # what????? Why can it update my object? It's lock in the other console!
testing2
中的lock!
不会锁定,而测试中的with_lock
可以正常工作。谁能解释为什么lock!
不起作用?
#lock!
使用SELECT ...用于更新以获取锁。
根据PostgreSQL文档。
FOR UPDATE 会导致 SELECT 语句检索的行被锁定,就像进行更新一样。这可以防止它们被其他事务锁定、修改或删除,直到当前事务结束。
您需要一个事务来保持对某一行的锁定。
尝试
控制台1:
Plan.transaction{Plan.find(12).lock!; sleep 100.days}
控制台2:
p = Plan.find(12)
p.name = 'should not be able to be stored in database'
p.save
#with_lock
为您获取交易,因此您不需要显式交易。
(这是PostgreSQL文档。但我认为其他数据库也实现了类似的逻辑。 )