Ari*_*osh 5 activerecord ruby-on-rails ruby-on-rails-5
我想要一个嵌套事务使父事务失败。
假设我有以下模型
class Task < ApplicationRecord
def change_status(status, performed_by)
ActiveRecord::Base.transaction do
update!(status: status)
task_log.create!(status: status, performed_by: performed_by)
end
end
end
Run Code Online (Sandbox Code Playgroud)
我总是希望创建update和task_log创建是一起执行的事务,或者根本不执行。
假设我有一个允许我更新多个任务的控制器
class TaskController < ApplicationController
def close_tasks
tasks = Task.where(id: params[:_json])
ActiveRecord::Base.transaction do
tasks.find_each do |t|
t.change_status(:close, current_user)
end
end
end
end
Run Code Online (Sandbox Code Playgroud)
我希望这样,如果任何一个change_status失败,整个请求都会从父级事务中回滚。
然而,这不是 Rails 中的预期行为,请参阅嵌套事务的文档
他们举了两个例子。
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)
这将创建Users“Kotori”和“Nemu”,因为父母永远不会看到加注
然后是下面的例子:
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”,因为只有嵌套事务失败了。
那么我怎样才能让 Rails 了解嵌套事务是否失败,从而导致父事务失败。继续上面的示例,我希望“Kotori”和“Nemu”都不会被创建。
您可以确保交易不可加入
User.transaction(joinable:false) do
User.create(username: 'Kotori')
User.transaction(requires_new: true, joinable: false) do
User.create(username: 'Nemu') and raise ActiveRecord::Rollback
end
end
Run Code Online (Sandbox Code Playgroud)
这将导致类似于以下内容的结果:
SQL (12.3ms) SAVE TRANSACTION active_record_1
SQL (11.7ms) SAVE TRANSACTION active_record_2
SQL (11.1ms) ROLLBACK TRANSACTION active_record_2
SQL (13.6ms) SAVE TRANSACTION active_record_2
SQL (10.7ms) SAVE TRANSACTION active_record_3
SQL (11.2ms) ROLLBACK TRANSACTION active_record_3
SQL (11.7ms) ROLLBACK TRANSACTION active_record_2
Run Code Online (Sandbox Code Playgroud)
您当前的示例结果如下
SQL (12.3ms) SAVE TRANSACTION active_record_1
SQL (13.9ms) SAVE TRANSACTION active_record_2
SQL (28.8ms) ROLLBACK TRANSACTION active_record_2
Run Code Online (Sandbox Code Playgroud)
当requires_new: true创建“新”事务(通常通过保存点)时,回滚仅适用于该事务。当该事务回滚时,它只是丢弃该事务并利用保存点。
通过使用requires_new: true, joinable: falserails,将为这些新事务创建保存点,以模拟真正的嵌套事务的概念,并且当调用回滚时,它将回滚所有事务。
你可以这样想:
requires_new: true阻止此事务加入其父事务joinable: false意味着父交易不能被子交易加入当使用两者时,您可以确保任何事务都不会被丢弃,并且任何地方的 ROLLBACK 都会导致任何地方的 ROLLBACK。
| 归档时间: |
|
| 查看次数: |
3245 次 |
| 最近记录: |