Rails:为什么这个PG交易不起作用?



我过去在许多应用程序中使用过事务,它们总是按预期工作,现在它们不是了。我想我只是在空白一些明显的东西......

为什么要创建第一条记录?

ActiveRecord::Base.transaction do
Order.create!(order_id: 12)
raise 'breaking now'
Order.create!(order_id: 13)
end

我正在使用Rails 6Postgres 12

编辑:现在什么都不起作用...我很困惑。这也不起作用(第一条记录更新(

ActiveRecord::Base.transaction do
order = Order.first
order.update(order_id: 777)
raise 'oops'
Order.create!(order_id: 13)
end

这个Order模型使用的是不同的数据库,但我在使用主数据库的模型上尝试了同样的事情,并且具有相同的效果。

class Order < ApplicationRecord
connects_to database: {reading: :orders, writing: :orders}
end

编辑:我也从一个新的rails c运行它,所以我的代码中没有嵌套事务,我没有在我的示例中显示。

我相信你正在寻找:

ActiveRecord::Base.connected_to(database: :replica) do
# you can probably execute plain sql transaction command here and then commit in the end instead of below...
Order.transaction do 
# ... all statements that need transaction wrapping from replica
end
end

此外,while_preventing_writes可以很方便:

ActiveRecord::Base.connected_to(role: :orders) do
Order.connection.while_preventing_writes do
# will raise because we're blocking writes
Order.create!
end
end
ActiveRecord::Base.connected_to(role: :orders) do
Order.connection.while_preventing_writes do
# will not raise as we're not writing
Order.first
end
end

语句可以来自不同的模型,但在单个块中,它们应该属于同一个数据库。 原因是:"事务不分布在数据库连接之间" - 这超出了 ActiveRecord 的范围(请参阅: https://api.rubyonrails.org/classes/ActiveRecord/Transactions/ClassMethods.html(

如果您确实需要跨来自不同数据库连接的模型进行事务,则必须使用文档中提到的解决方法:

Student.transaction do
Course.transaction do
course.enroll(student)
student.units += course.units
end
end

在这方面,一些可能允许更简单的API的改进似乎在Rails 6.1中按计划进行。如果您想了解更多信息 - 请参阅例如此评论和引用的 PR。

最新更新