ruby 使用嵌套事务

jjjwad0x  于 2023-04-20  发布在  Ruby
关注(0)|答案(1)|浏览(185)

我认为嵌套事务是用来把事务分开的,如下所示。

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

但是代码将同时生成KotoriNemu。如果只得到Kotory,应该在下面。

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

但是为什么呢?为什么我们需要显式地使用requires_new选项?requires_new: false有什么用例吗?
谢谢
reference:https://API.rubyonrails.org/classes/ActiveRecord/Transactions/ClassMethods.html#:~:text= ActiveRecord%3A%3ASatementInvalid%20occurred.-,Nested%20transactions,-transaction%20calls%20can

bq8i3lrv

bq8i3lrv1#

嵌套事务以这种方式工作是因为 * 嵌套事务块成为父事务的一部分 *。它以这种方式实现是因为 * 大多数数据库不支持真正的嵌套事务 *。
而且,由于是否支持嵌套事务取决于所使用的数据库系统,因此RubyonRails不能将不那么令人惊讶的选项作为默认行为。
这在关于Rails中嵌套事务的文档中有解释:

嵌套交易

transaction调用可以嵌套。默认情况下,这会使嵌套事务块中的所有数据库语句成为父事务的一部分。例如,以下行为可能会令人惊讶:

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

创建“Kotori”和“Nemu”。原因是嵌套块中的ActiveRecord::Rollback异常不会发出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”被创建。
大多数数据库不支持真正的嵌套事务。在撰写本文时,我们所知道的唯一支持真正的嵌套事务的数据库是MS-SQL。因此,Active Record通过使用保存点来模拟嵌套事务。dev.mysql.com/doc/refman/en/savepoint.html有关保存点的详细信息,请参阅www.example.com。

相关问题