Mik*_*rin 17 ruby mysql activerecord transactions ruby-on-rails
根据文档ActiveRecord :: Transactions :: ClassMethods,非新嵌套事务将忽略回滚.来自文档:
User.transaction do
User.create(username: 'Kotori')
User.transaction do
User.create(username: 'Nemu')
raise ActiveRecord::Rollback
end
end
Run Code Online (Sandbox Code Playgroud)
该raise ActiveRecord::Rollback
被忽略,因为它是在一个子事务(或者更确切地说,它仍然是在父事务中,而不是自己的).我不明白为什么两个都会忽略回滚调用?我可以看到,因为子'事务'不是真正的事务,它不会回滚'Nemu'块,但为什么它不会触发父项的回滚?子事务是否以某种方式隐藏了回滚?
换句话说,为什么似乎无法从嵌套子项中回滚父事务?
Nim*_*mir 15
实际上,这正是嵌套交易的设计方式.我引用oracle文档:
嵌套事务用于为在较大事务范围内执行的操作子集提供事务保证.这样做允许您独立于较大的事务提交和中止操作子集.
因此,常规嵌套事务中的子事务对于他或其他子项或父项(较大事务)的行为方式没有发言权,除了更改相互数据或未能发生异常.
但是你可以通过传递使用rails docs中所述的功能,给予他(儿童交易)一个非常有限的投票机会.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
Run Code Online (Sandbox Code Playgroud)
正如文档所说:只创造'Kotori'.因为强大的'Nemu'孩子选择了默默地死去.
有关嵌套事务规则的更多详细信息(oracle docs)
更新:
为了更好地理解为什么rails以nested transactions
这种方式工作,你需要更多地了解嵌套事务如何在数据库级别工作,我引用rails api docs:
大多数数据库不支持真正的嵌套事务...为了解决这个问题,#transaction将使用保存点模拟嵌套事务的影响:http://dev.mysql.com/doc/refman/5.0/ EN/savepoint.html
好的,然后文档描述了nested transaction
上述两种情况中a的行为如下:
在嵌套调用的情况下,#transaction将表现如下:
该块将在不执行任何操作的情况下运行.块内发生的所有数据库语句都有效地附加到已打开的数据库事务中.
但是,如果设置了:requires_new,则该块将被包装在充当子事务的数据库保存点中.
我想小心,只想象:
选项(1)(没有 requires_new)是为了防止您使用完全支持的DBMS,nested transactions
或者您对"假"行为感到满意nested_attributes
而选项(2)是支持savepoint
解决方法,如果你不支持.
这是因为transaction do
块如何专门处理ActiveRecord::Rollback
在这些块中引发的异常以及 Railstransaction do
默认如何将嵌套块连接在一起的交互。
transaction do
根据其中引发的异常类型,Rails块的行为略有不同:
ActiveRecord::Rollback
内引发异常时transaction do
,这些异常会被transaction do
块拯救,并且不会进一步冒泡。transaction do
块做继续泡了超越该块。默认情况下,Rails 将嵌套事务“连接”在一起。这意味着只有当最外部的事务有异常冒泡时,事务才会被中止。
总之,这两种行为意味着,当ActiveRecord::Rollback
在嵌套事务中提出的,它是由内部救出transaction do
块确实不能再提升; 外部transaction do
块,因为它没有收到异常,成功完成。
要强调,如果你提出任何异常其他比ActiveRecord::Rollback
,它会继续向上冒泡通过多个transaction do
模块和外部交易将中止预期。
正如在别处提到的,你可以强制 Rails 的嵌套事务不“加入”它们的父事务transaction(requires_new: true) do
;以及强制具有transaction(joinable: false) do
. 它被推荐为始终同时使用transaction(joinable: false, requires_new: true) do
归档时间: |
|
查看次数: |
4765 次 |
最近记录: |