此代码不常见
我正在编写一个长期运行事务(使用Web API)
所以,我需要棘手的程序
我想重新保存回滚对象(piyo2
)。
piyo2 = nil
ActiveRecord::Base.transaction do
piyo1 = Piyo.find_by(id: 1)
piyo1.name = 'hoge'
piyo1.save!
piyo2 = Piyo.find_by(id: 2)
piyo2.name = 'foo'
piyo2.save!
raise ActiveRecord::Rollback
end
piyo2.save! # log show BEGIN COMMIT. But Not show execute SQL.
piyo2.name # keep foo. But DB no change.
我的解决方案。
piyo2 = nil
ActiveRecord::Base.transaction do
piyo1 = Piyo.find_by(id: 1)
piyo1.name = 'hoge'
piyo1.save!
piyo2 = Piyo.find_by(id: 2)
piyo2.name = 'foo'
piyo2.save!
raise ActiveRecord::Rollback
end
piyo2_retry = Piyo.find_by(id: piyo2.id) # one more find_by
piyo2_retry.update!(name: piyo2.name)
这是最好的解决方案吗?
为什么piyo2.save! # log show BEGIN COMMIT. But No execute SQL.
这段代码没有炒作?
答案 0 :(得分:0)
你基本上做的是正确的事,尽管你的例子让我有些困惑。
以下是您所看到的为什么。
您必须刷新手头实例的状态。
即使你回滚了事务,你手中的实例仍然认为它是持久的并且具有新名称。你可以通过调用来证明这一点:
puts piyo2.name # foo
puts piyo2.persisted? # true
puts piyo2.changed? # falses
如果对象当前持久且没有更改,则Rails足够聪明,不会实际运行SQL。您可以通过加载任何对象并立即尝试保存它来证明这一点。您将在日志/输出中看到BEGIN / COMMIT没有其他SQL。
实际上,您的对象不再与数据库同步。为了使实例的状态与db同步,您必须重新加载它:
piyo2.reload
这是你有效的做法。 Piyo.find piyo2.id
生成与重新加载完全相同的SQL。重新加载只是在语义上更清晰。