3

与提交数据库更新后运行 rails 代码相关,没有 after_commit,但我认为值得提出自己的问题。

如果我有这样的代码:

my_instance = MyModel.find(1)
MyModel.transaction do 
  my_instance.foo = "bar"
  my_instance.save!
end
new_instance = MyModel.find(1)
puts new_instance.foo

这是始终输出“bar”而不是其先前值的保证吗new_instance.foo我正在寻找一种方法来确保在执行我的下一个语句之前提交上一个语句中发生的所有数据库操作。Rails 对此有一个 after_commit 钩子,但我不希望每次都执行此代码……仅在此特定上下文中。

我在 Transactions 文档中找不到任何表明 Transaction 块是否“阻塞”的内容。如果他们阻塞,那将满足我的要求。不幸的是,我想不出一种实用的方法来测试这种行为,以某种方式证实我的怀疑。

4

1 回答 1

3

仍在研究这一点,但我认为事务确实会阻止代码执行,直到数据库确认它已写入。由于“保存!” 由 Rails 自动包装在事务中,相关代码应同步运行。额外的事务块应该是不必要的。

当数据库调用在事务中时,我认为 Rails 不会立即返回对数据库的调用。我对 after_save 回调感到困惑。After_save 回调受到竞争条件的影响,因为它们实际上是保存自动包装的事务的一部分,因此 after_save 回调调用的任何代码都不是竞争条件安全的,它不受事务保护。只有 after_commit 调用是安全的。在事务中,Rails 将移交给数据库,然后在数据库完成提交之前执行 after_save 回调。

研究这个以获得更多见解:

https://github.com/rails/rails/blob/bfdd3c2182156fa2cb81ed4f048b065a2d6f1341/activerecord/lib/active_record/connection_adapters/abstract/transaction.rb

更新

将我的答案改为“不”。好像没救了!或保存块执行。从这两个资源中,看起来这是一个常见的问题:

https://github.com/resque/resque/wiki/FAQ#how-do-you-make-a-resque-job-wait-for-an-activerecord-transaction-commit

https://blog.engineyard.com/2011/the-resque-way

于 2013-08-17T21:23:02.187 回答