在所有操作都提交之后,rails事务块是否会退出?

时间:2022-07-20 22:46:47

Related to Run rails code after an update to the database has commited, without after_commit, but I think deserving its own question.

在数据库更新后运行rails代码已经开始,而没有after_commit,但是我认为应该有自己的问题。

If I have code like this:

如果我有这样的代码:

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

Is this a guarantee that new_instance.foo will always output "bar" and not its previous value? I'm looking for a way to ensure that all the database actions that occur in a previous statement are committed BEFORE executing my next statements. Rails has an after_commit hook for this, but I don't want this code executed every time... only in this specific context.

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

I can't find anything in the documentation on Transactions that would indicate if Transaction blocks are "blocking". If they are blocking, that will satisfy my requirement. Unfortunately, I can't think of a practical way to test this behavior to confirm my suspicions one way or another.

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

1 个解决方案

#1


3  

Still researching this, but I think a transaction does block code execution until after the database confirms that it has written. Since "save!" is automatically wrapped in a transaction by Rails, the relevant code should run synchronously. The extra transaction block should be unnecessary.

仍然在研究这个问题,但是我认为事务在数据库确认它已经编写之后才会阻止代码执行。由于“save!”被Rails自动包装在事务中,因此相关代码应该同步运行。额外的事务块应该是不必要的。

I don't think Rails returns as soon as it hands off the call to the DB when the DB calls are within a transaction. The confusion I had was with after_save callbacks. After_save callbacks suffer from race conditions because they are in fact part of the transaction that saves are automatically wrapped in, so any code called by an after_save callback is not race condition safe, it is not protected by the transaction. Only after_commit calls are safe. Within the transaction Rails will hand off to the DB and then execute after_save callbacks before the DB has finished committing.

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

Studying this for more insights:

为了获得更多的见解,我们来研究一下这个问题:

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

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

UPDATE

更新

Changing my answer to "no". It doesn't appear that save! or save blocks execution. From these two resources, looks like this is a common problem:

把我的答案改成“不”。看起来没有保存!或保存块执行。从这两个资源来看,这似乎是一个常见的问题:

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

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

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

#1


3  

Still researching this, but I think a transaction does block code execution until after the database confirms that it has written. Since "save!" is automatically wrapped in a transaction by Rails, the relevant code should run synchronously. The extra transaction block should be unnecessary.

仍然在研究这个问题,但是我认为事务在数据库确认它已经编写之后才会阻止代码执行。由于“save!”被Rails自动包装在事务中,因此相关代码应该同步运行。额外的事务块应该是不必要的。

I don't think Rails returns as soon as it hands off the call to the DB when the DB calls are within a transaction. The confusion I had was with after_save callbacks. After_save callbacks suffer from race conditions because they are in fact part of the transaction that saves are automatically wrapped in, so any code called by an after_save callback is not race condition safe, it is not protected by the transaction. Only after_commit calls are safe. Within the transaction Rails will hand off to the DB and then execute after_save callbacks before the DB has finished committing.

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

Studying this for more insights:

为了获得更多的见解,我们来研究一下这个问题:

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

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

UPDATE

更新

Changing my answer to "no". It doesn't appear that save! or save blocks execution. From these two resources, looks like this is a common problem:

把我的答案改成“不”。看起来没有保存!或保存块执行。从这两个资源来看,这似乎是一个常见的问题:

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

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

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