根据文档ActiveRecord :: Transactions :: ClassMethods,一个非新的嵌套事务将忽略回滚。从文档:
User.transaction do User.create(username: 'Kotori') User.transaction do User.create(username: 'Nemu') raise ActiveRecord::Rollback end end
该raise ActiveRecord::Rollback被忽略,因为它是在一个子事务(或者更确切地说,它仍然是在父事务中,而不是自己的)。我不明白为什么两者都会忽略Rollback调用?我可以看到,由于子级’transaction’并不是真正的事务,它不会回滚’Nemu’块,但是为什么它不触发父级的回滚?子事务是否以某种方式隐藏了回滚?
raise ActiveRecord::Rollback
换句话说,为什么似乎没有办法从嵌套子项中回滚父事务?
实际上,这正是 嵌套事务 设计的目的。我引用oracle文档:
嵌套事务用于为较大事务范围内执行的操作的子集提供事务保证。这样做使您可以独立于较大的事务来提交和中止操作的子集。
因此,常规 嵌套事务中 的子事务除了更改相互数据或失败失败外,没有其他关于他或其他孩子或父母( 较大事务 )的行为的发言权。
但是,你可以给他( 子事务 利用)对他命运的一个非常有限的投票机会,sub- transaction特征为在轨说明文档通过传递requires_new: true
sub- transaction
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
正如文档所说:仅创建“ Kotori”。因为强大的“ Nemu”孩子选择默默地死。
有关 嵌套事务处理规则的 更多详细信息(oracle docs)
更新:
为了更好地理解Rails为何如此nested transactions工作,您需要更多地了解嵌套事务在数据库级别的工作方式,我引用了rails api docs:
nested transactions
大多数数据库不支持真正的嵌套事务…为了解决此问题,#transaction将通过使用保存点来模拟嵌套事务的效果:http ://dev.mysql.com/doc/refman/5.0/ zh / savepoint.html
好的,然后文档描述了nested transaction上述两种情况下a的行为,如下所示:
nested transaction
如果发生嵌套调用,则#transaction的行为如下:
该块将不执行任何操作。块中发生的所有数据库语句都有效地附加到已经打开的数据库事务中。
但是,如果设置了:requires_new,则该块将被包装在充当子事务的数据库保存点中。
我想 小心,只想想 :
*如果您使用的是完全支持的DBMS, 或者您对以下选项的“假”行为感到满意,则可以使用 *option(1) ( 不带 require_new)nested transactions:nested_attributes
nested_attributes
如果不支持,则 option(2) 支持该savepoint解决方法。
savepoint