这是我的课程:
class Plan < ActiveRecord::Base
def testing
self.with_lock do
update_columns(lock: true)
byebug
end
end
def testing2
self.lock!
byebug
end
end
我打开了两个Rails控制台。
在第一个控制台中:
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!
lock!
中的 testing2
不会锁定,而测试中的with_lock
却可以工作。谁能解释为什么lock!
不起作用?
答案 0 :(得分:2)
#lock!
使用SELECT…FOR UPDATE获取锁。
根据{{3}}。
FOR UPDATE导致SELECT语句检索的行被锁定,就像更新一样。这样可以防止它们在当前事务结束之前被其他事务锁定,修改或删除。
您需要一个事务来保持一定行的锁。
尝试
console1:
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文档。但是我认为其他数据库也实现了类似的逻辑。)