与 Mongoid 交易的上下文

Context in transactions with Mongoid

我需要使用 mongoid 的事务来执行一些操作,同时在发生故障时保持一致性。

official documentation 之后,我了解到我必须在模型上启动会话并在 start_transactioncommit_transaction 之间执行操作。

我不明白的是我必须在特定模型或模型实例上实例化会话。

我不知道是不是因为模型有一个助手来执行该操作(由于 beign Monogid::Document)或者我必须执行的操作必须与 model/instance 有关使用过。

我的意思是,我是否可以执行此操作(我知道这或多或少是错误的,因为这些模型可能完全不相关):

ModelA.with_session do |s|
  s.start_transaction
  TotallyUnrelatedModelA.create!
  TotallyUnrelatedModelB.create!
  TotallyUnrelatedModelC.create!
  s.commit_transaction
end

有人知道原因吗?

Mongoid 目前不执行(或没有)事务。这是驱动程序的功能。

您不应该调用 commit_transaction,因为这是驱动程序公开的事务 API 的第一次迭代,并且不支持自动重试。不幸的是,Mongoid 文档尚未更新以显示正确的 API 用法 - 它是 here.

中描述的 with_transaction 方法

要在驱动程序级别使用事务,启动事务的会话必须手动传递给每个操作,如 in the same doc 所示。

Mongoid 通过所谓的持久性上下文 没有该要求。这个功能有点描述 here,它的要点是你可以覆盖在运行时读取或写入模型的位置,例如写入另一个集合。

会话是通过相同的运行时覆盖实现的。回顾this pagewith_session 方法从活动持久性上下文中检索 client,然后确保 1) 在该客户端上有一个活动的会话,以及 2) 活动持久性上下文与之相关联会话,以便 3) 每个持久性操作(读取和写入)都将向驱动程序指定该会话。

现在,回答你的问题:

The thing I do not understand is the fact that I have to instantiate a session on a specific model or instance of a model.

Mongoid 需要知道在哪个客户端上启动会话。它可以从任何持久性上下文中获取该客户端。使用模型 class 还是模型实例并不重要。因为在 Mongoid 中一次只能有一个会话处于活动状态(会话存储在当前线程的线程本地存储中),您必须仅使用与用于启动会话的同一客户端相关联的模型,通过with_session 方法,无论 Mongoid 如何到达客户端(通过模型 class 或模型实例)。