为什么Rails的忽略了(伪)嵌套事务回滚? [英] Why does Rails ignore a Rollback in a (pseudo)nested transaction?

查看:160
本文介绍了为什么Rails的忽略了(伪)嵌套事务回滚?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

按照该文档<一href="http://api.rubyonrails.org/classes/ActiveRecord/Transactions/ClassMethods.html">ActiveRecord::Transactions::ClassMethods,非新的嵌套事务会忽略回滚。从文档:

  User.transaction办
  User.create(用户名:'小鸟')
  User.transaction做
    User.create(用户名:音梦)
    提高的ActiveRecord ::回滚
  结束
结束
 

募集的ActiveRecord ::回滚被忽略,因为它是在一个子事务(或者更确切地说,它仍然是在父事务中,而不是自己的)。我不明白为什么回滚通话将被这两个被忽略?我可以看到,既然孩子交易是不是一个真正的交易,它不会回滚音梦块,但为什么它不会触发回退父?孩子是否交易隐藏回滚不知何故?

在换句话说,那为什么似乎有没有办法从一个嵌套的子回滚父事务?

解决方案

其实这正是嵌套事务是专为。我引用的Oracle文档:

  

一个嵌套事务用于提供跨国保障   操作的子集的一个较大的范围内进行   交易。这样做可以使您可以提交和中止的子集   操作的独立地较大的事务

所以,在一个普通的嵌套事务的子事务具有对于没有说怎么他或其他孩子或家长(的大交易的)可能会做人,不是改变相互其他数据或失败的一个例外。

但你可以给他(的子事务的)一个关于他的命运通过利用子事务功能非常有限投票权的机会,因为在规定的轨文档通过传递 REQUIRES_NEW:真正的

  User.transaction办
  User.create(用户名:'小鸟')
  User.transaction(REQUIRES_NEW:真)办
    User.create(用户名:音梦)
    提高的ActiveRecord ::回滚
  结束
结束
 

其中的文档说:只创建小鸟。因为强大的音梦的孩子选择了默默死去。

关于嵌套事务规则甲骨文文档

更新:

要更好地理解为什么轨嵌套事务以这种方式工作,你需要知道一点关于如何嵌套事务在数据库级的作品,我从导轨API文档

  

大多数数据库不支持真正的嵌套事务。为了   解决这个问题,#transaction将模拟的效果   嵌套事务,使用保存点:    http://dev.mysql.com/doc/refman/5.0/en /savepoint.html

好吧,那么文档描述如下两个提到的情况下,嵌套事务的行为:

在情况下,嵌套调用, #transaction 将表现为如下:

  • 该块将不做任何运行。发生块内的所有数据库语句有效地附加到已经打开的数据库事务。

  • 然而,如果:REQUIRES_NEW被设置,该块将被包裹在一个数据库保存点充当子事务

我想象的小心,只能想象的是:

选项(1)没有 REQUIRES_NEW)有没有在您使用DBMS的情况下,充分支持嵌套事务或者你很高兴与 nested_attributes

,而选项(2)是支持保存点解决方法,如果你不这样做。

As per the docs ActiveRecord::Transactions::ClassMethods, a non-new nested transaction will ignore a Rollback. From the docs:

User.transaction do
  User.create(username: 'Kotori')
  User.transaction do
    User.create(username: 'Nemu')
    raise ActiveRecord::Rollback
  end
end

The raise ActiveRecord::Rollback is ignored because it is in a child transaction (or rather, it is still within the parent transaction and not its own). I do not understand why the Rollback call would be ignored by both? I can see that since the child 'transaction' isn't really a transaction, that it would not roll back the 'Nemu' block, but why does it not trigger a rollback for the parent? Does the child transaction hide the rollback somehow?

In other words, why is it that there appears to be no way to roll back a parent transaction from within a nested child?

解决方案

Actually this is exactly how Nested Transactions was designed for. I quote from oracle docs:

A nested transaction is used to provide a transnational guarantee for a subset of operations performed within the scope of a larger transaction. Doing this allows you to commit and abort the subset of operations independently of the larger transaction.

So, a child transaction in a regular nested transaction has no say regarding how him or the other children or parent (larger transaction) could behave, other than changing mutual data or failing for an exception.

But you can grant him (child transaction) a very limited voting chance on his destiny by utilizing the sub-transaction feature as stated at rails docs by passing requires_new: true

User.transaction do
  User.create(username: 'Kotori')
  User.transaction(requires_new: true) do
    User.create(username: 'Nemu')
    raise ActiveRecord::Rollback
  end
end

Which as the docs say: only creates 'Kotori'. since the powerful 'Nemu' child chose to die silently.

More details about Nested transaction rules (oracle docs)

Update:

To better understand why rails nested transactions works this way, you need to know a bit more about how nested transactions works in DB level, i quote from rails api docs:

Most databases don’t support true nested transactions ...In order to get around this problem, #transaction will emulate the effect of nested transactions, by using savepoints: http://dev.mysql.com/doc/refman/5.0/en/savepoint.html

Ok, then the docs describes the behavior of a nested transaction in the two mentioned cases as follows:

In case of a nested call, #transaction will behave as follows:

  • The block will be run without doing anything. All database statements that happen within the block are effectively appended to the already open database transaction.

  • However, if :requires_new is set, the block will be wrapped in a database savepoint acting as a sub-transaction.

I imagine careful, only imagine that:

option(1) (without requires_new) is there in case you used a DBMS that fully supports nested transactions or you are happy with the "fake" behavior of nested_attributes

while option(2) is to support the savepoint workaround if you don't.

这篇关于为什么Rails的忽略了(伪)嵌套事务回滚?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆