ruby-on-rails - 数据库锁在 Rails 和 Postgres 中无法正常工作

标签 ruby-on-rails ruby postgresql transactions locking

我在 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

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

在控制台测试 with_lock 的效果证实了我的预期。然而,在生产中,似乎在某些或所有情况下锁都没有按预期工作,并且正在尝试冗余 Bar —— 因此,with_lock 不会(总是?)导致代码等待轮到它.

这里会发生什么?

更新 对所有说“锁定 foo 不会帮助你”的人感到抱歉!我的示例最初没有栏查找。现在已修复。

最佳答案

您对 with_lock 的作用感到困惑。来自fine manual :

with_lock(lock = true)

Wraps the passed block in a transaction, locking the object before yielding. You pass can the SQL locking clause as argument (see lock!).

如果您检查一下 with_lock 内部做了什么,您会发现它只不过是一个围绕 lock! 的薄包装而已。 :

lock!(lock = true)

Obtain a row lock on this record. Reloads the record to obtain the requested lock.

所以 with_lock 只是进行行锁定并锁定 foo 的行。

不要为所有这些锁定废话而烦恼。处理这种情况的唯一明智的方法是在数据库中使用唯一性约束,只有数据库才能确保唯一性,除非您想做一些荒谬的事情,例如锁定整个表;然后继续并盲目地尝试您的 INSERT 或 UPDATE 并捕获并忽略在违反唯一约束时将引发的异常。

关于ruby-on-rails - 数据库锁在 Rails 和 Postgres 中无法正常工作,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11313303/

相关文章:

ruby-on-rails - Capistrano 3,使用上传!在 lib/capistrano/tasks 的任务中

ruby-on-rails - 如何使 ID 成为 Rails 中的随机 8 位字母数字?

sql - 基于 hstore 键的动态 INSERT 语句

spring - 回滚已检查和未检查异常的事务

javascript - 用coffeescript中的图像替换文本

ruby-on-rails - rails : Good process for adding tests retroactively?

mysql - 用于将实时 (MySQL) 数据库加载到本地开发数据库的 Rails rake 任务

ruby - 是否可以在 Ruby 1.8.6 上安装 RubyGems?

ruby - 使用 Chef 和 Vagrant 在 Ubuntu 上安装 Ruby 1.9.2

javascript - 是否可以在 postgreSQL 中将表 A ID 索引到表 B userId?