示例:
BillingProfile.transaction do
if @billing_profile.save
unless SomeService.do_something # returns false and rollback occurs
raise ActiveRecord::Rollback
end
end
end
@billing_profile.persisted? # Still return true, despite rollback
@billing_profile.id # Is set, despite rollback
为什么@billing_profile的状态不反映该记录已回滚?
这是一个问题,因为记录在回滚后无法创建。
原来这是ActiveRecord(Rails 4)中的一个错误:https://github.com/rails/rails/issues/13744
现在已经修复。
我对事务的工作方式很感兴趣。文档中解释了您的具体场景。引用文档
事务调用可以嵌套。默认情况下,这会使所有数据库嵌套事务块中的语句成为父级的一部分交易例如,以下行为可能令人惊讶:
User.transaction do User.create(username: 'Kotori') User.transaction do User.create(username: 'Nemu') raise ActiveRecord::Rollback end end
创造了"Kotori"one_answers"Nemu"。原因是ActiveRecord::回滚嵌套块中的异常不会发出ROLLBACK。由于这些异常在事务块中捕获,父块则捕获看不到它,并且提交了真正的事务。
为了获得嵌套事务的ROLLBACK,您可能会要求通过传递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"。这适用于MySQL和PostgreSQL。SQLite3版本>='3.6.8'也支持它。
大多数数据库不支持真正的嵌套事务。在写作,我们所知道的唯一支持true的数据库嵌套事务是MS-SQL。正因为如此,Active Record通过在MySQL和PostgreSQL。请参阅dev.mysql.com/doc/refman/5.6/en/savepoint.html有关保存点的详细信息。