使用Rails和Postgres,数据库锁定无法正常工作

Joh*_*hir 9 ruby postgresql locking transactions ruby-on-rails

我在rails模型中有以下代码:

foo = Food.find(...)
foo.with_lock do
  if bar = foo.bars.find_by_stuff(stuff)
    # do something with bar
  else
    bar = foo.bars.create!
    # do something with bar
  end
end
Run Code Online (Sandbox Code Playgroud)

目标是确保创建的类型的Bar不会被创建两次.

在控制台上测试with_lock工作确认了我的期望.但是,在生产中,似乎在某些或所有情况下锁都没有按预期工作,并且正在尝试冗余Bar - 因此,with_lock不会(总是?)导致代码等待轮到.

这可能发生什么?

更新 对所有说"锁定foo不会帮助你"的人抱歉!我的例子最初没有查找条形码.这是现在修复的.

mu *_*ort 7

你对这是什么感到困惑with_lock.从精细手册:

with_lock(lock = true)

在事务中包装传递的块,在屈服之前锁定对象.您可以将SQL锁定子句作为参数传递(请参阅参考资料lock!).

如果你检查一下with_lock内部是什么,你会发现它只是一个薄的包装器lock!:

锁!(lock = true)

获取此记录的行锁定.重新加载记录以获取请求的锁定.

所以with_lock只是做一个行锁和锁foo的行.

不要打扰所有这些锁定废话.处理这种情况的唯一理智方法是在数据库中使用唯一约束,除了数据库之外没有人可以确保唯一性,除非你想做一些荒谬的事情,比如锁定整个表; 然后继续并盲目地尝试INSERT或UPDATE并陷阱并忽略在违反唯一约束时将引发的异常.


Dam*_*kić 1

锁在 Rails 应用程序的查询缓存中不起作用的原因。

如果您尝试在单个请求中多次获取同一行上的独占锁,则查询缓存将启动,因此后续锁定查询永远不会到达数据库本身。

该问题已在 Github 上报告。