Ruby on Rails多保存操作事务回滚失效的原因与解决方法
问题解析与解决方案
你的理解误区
你对save/save!自带独立事务的推测完全正确。ActiveRecord中,#save和#save!方法默认会基于数据库保存点开启独立子事务。在外层事务块中调用这些方法时,每一次save!都会完成子事务的提交;当第三个save!触发错误时,只会回滚自身对应的子事务(即最后一次保存操作),前两次已提交的子事务变更不会被外层事务的回滚影响。
代码调整方案
要实现出错时回滚所有操作,确保所有变更处于同一个外层事务中,可采用以下两种方式:
方式一:使用create!直接创建记录
create!方法不会额外开启子事务,会直接在外层事务上下文里执行创建逻辑:
ActiveRecord::Base.transaction do User.create!(username: "michael") User.create!(username: "lebron") User.create!(username: "michael") # 非唯一约束错误 end
方式二:禁用save!的自动子事务
如果需要保留new初始化对象的流程,可以给save!传递transaction: false参数,跳过其自带的子事务逻辑:
ActiveRecord::Base.transaction do user1 = User.new(username: "michael") user1.save!(transaction: false) user2 = User.new(username: "lebron") user2.save!(transaction: false) user3 = User.new(username: "michael") user3.save!(transaction: false) # 非唯一约束错误 end
上述两种方案中,一旦第三个操作触发唯一约束错误,整个外层事务会回滚,前两次创建的记录都会被撤销。
内容的提问来源于stack exchange,提问作者Dariusz Mydlarz
相关产品推荐
相关产品推荐

