转义 ActiveRecord 事务

Escape an ActiveRecord transaction

提问人:schmijos 提问时间:8/17/2023 更新时间:8/17/2023 访问量:45

问:

如何转义 ActiveRecord 事务?请考虑以下代码:

Model1.transaction do
  response = http.request(request)
  OutboundRequestLog.create(request:, response:)

  # … do stuff with Model1

  raise ActiveRecord::Rollback
end

OutboundRequestLog是一个 ActiveRecord 模型,应独立于事务进行持久化。上面的代码也会导致回滚。Model1OutboundRequestLog

是否有可能以某种方式从当前事务中排除查询? 我已经尝试了以下方法:

  1. 获取新的数据库连接 这里的缺点是水豚似乎不能很好地应对。我不确定问题是事务性固定装置还是执行器线程。
    
    Thread.new do
     ActiveRecord::Base.connection_pool.with_connection do
       OutboundRequestLog.create(request:, response:)
     end
    end.value
    
  2. 通过 ActiveJob#perform_later 延迟日志记录并不容易,因为 net/http 请求不容易序列化,并且序列化的有效负载可能很大。
Ruby-on-Rails 数据库 ActiveRecord

评论

1赞 dbugger 8/17/2023
有什么原因不能在输入交易之前创建日志?
0赞 schmijos 8/17/2023
这个东西的设计比我在这里描述的要复杂一些。它涉及复杂的 AR 验证以及一整套其他模型和 HTTP 请求。
0赞 schmijos 8/17/2023
我在这里添加了我最终得到的内容:github.com/renuo/rails_api_logger/blob/main/README.md#caveats

答:

2赞 smathy 8/17/2023 #1

顺便说一句,将需要很长时间(就数据库世界而言需要很长时间,即超过~几十毫秒)的东西放入数据库事务中通常不是一个好主意,例如。HTTP 请求。您应该在进入事务之前执行此操作(因此,在您的用例中,您可以在进入事务之前登录),然后打开事务以仅执行与数据库相关的操作。

其他选项是使用子句配置模型以使用不同的数据库连接(在此处查看更多信息),或者您可以手动检连接,只需知道您需要重新检入即可。我会将这种复杂性隐藏在方法中。OutboundRequestLogconnects_toOutboundRequestLog

虽然它主要用于副本和分片,但我通常会使用这种方法。它更整洁,手动更少(老实说,如果我登录到数据库,我总是会认为最终我会想要一个专用的数据库,这样我就不会影响我的用户体验)connects_to

评论

0赞 schmijos 8/17/2023
很酷的想法使用.我读了起来。它应该开箱即用,因为它似乎不是故意的 您能否进一步详细说明为什么数据库事务不应该花费很长时间?如果我不锁定并且范围很窄,我看不出有什么问题。connects_toRails uses the model class name for the connection specification nameIt's important to connect to your database in a single model and then inherit from that model for the tables rather than connect multiple individual models to the same database.
0赞 smathy 8/18/2023
是的,因为事务打开的时间越长,提交时序列化失败的可能性就越大。