什么ActiveRecord Transaction不会回滚?

问题描述 投票:0回答:1

我希望 ActiveRecord 事务故意失败。问题是,当我引发 ActiveRecord::Rollback 异常(或任何其他异常)时,回滚不会发生。在下面的代码中,

perfom
方法导入一个文件。为了简单起见,我们假设它只是更新一条记录:

puts "+++ Before Transaction +++"

ActiveRecord::Base.transaction do
  puts "+++ In Transaction +++"
  perform

  puts "+++ Before Rollback +++"
  raise ActiveRecord::Rollback
end

puts "+++ After Transaction +++"

当代码运行时,这是服务器的输出:

+++ Before Transaction +++
+++ In Transaction +++
TRANSACTION (0.1ms)  BEGIN
↳ app/models/import.rb:103:in `file_content'
Disk Storage (0.1ms) Downloaded file from key: abcdefg
Car Load (0.2ms)  SELECT "cars".* FROM "cars" WHERE "cars"."make" = '207' LIMIT 1
↳ app/models/application_record.rb:82:in `try_update_or_create_report'
Car Exists? (0.3ms)  SELECT 1 AS one FROM "rolling_shutters_automatism_prices" WHERE 
"cars"."make" = '207' AND "cars"."id" != 5 LIMIT 1
↳ app/models/application_record.rb:106:in `try_update_report'
Car Update (0.2ms)  UPDATE "cars" SET "price" = 20.0, "updated_at" = '2023-12-26 15:17:47.978023' WHERE "cars"."id" = 5
↳ app/models/application_record.rb:106:in `try_update_report'
+++ Before Rollback +++
+++ After Transaction +++

我期望的行为是在最后两行之间登录

ROLLBACK
,但没有记录任何内容。这是为什么?

我使用 Rails 7.0.4 和 postgres 15 和 ruby 3.2.2

编辑:我遗漏了一条重要信息。事务发生在 ActiveRecord 回调中。

ruby-on-rails activerecord
1个回答
0
投票

问题在于事务发生在 ActiveRecord 回调内。由于回调“本身包装在事务中”,因此我尝试执行的事务是“嵌套事务”。因此,引发 ActiveRecord::Rollback 异常会导致外部事务回滚。 根据文档:

为了获得嵌套事务的回滚,您可以通过传递requires_new: true来请求真正的子事务。如果出现任何问题,数据库将回滚到子事务的开头,而不回滚父事务。

因此固定示例如下所示:

puts "+++ Before Transaction +++" ActiveRecord::Base.transaction(requires_new: true) do puts "+++ In Transaction +++" perform puts "+++ Before Rollback +++" raise ActiveRecord::Rollback end puts "+++ After Transaction +++"

© www.soinside.com 2019 - 2024. All rights reserved.