MongoDB的存储库模式-一项事务可处理多个工作单元

Met*_*eny 8 c# transactions unit-of-work repository-pattern mongodb

我正在使用“存储库+工作单元”模式在C#Mongo DB驱动程序的顶部实现DAL抽象层。我当前的设计是每个工作实例实例都将打开(和关闭)新的Mongo DB会话。问题是Mongo DB仅允许会话和事务之间的1:1比率,因此在同一.NET事务下无法进行多个工作单元。

当前的实现是:

public class MongoUnitOfWork
{
    private IClientSessionHandle _sessionHandle;

    public MongoUnitOfWork(MongoClient mongoClient)
    {
       _sessionHandle = mongoClient.StartSession();
    }

    public void Dispose()
    {
       if (_sessionHandle != null)
       {
          // Must commit transaction, since the session is closing
          if (Transaction.Current != null)
            _sessionHandle.CommitTransaction();
          _sessionHandle.Dispose();
       }
    }
}
Run Code Online (Sandbox Code Playgroud)

因此,以下代码将不起作用。第一批数据将提前提交:

using (var transactionScope = new TransactionScope())
{
    using (var unitOfWork = CreateUnitOfWork())
    {
       //... insert items

       unitOfWork.SaveChanges();
    }  // Mongo DB unit of work implementation will commit the changes when disposed

    // Do other things

    using (var unitOfWork = CreateUnitOfWork())
    {
       //... insert some more items
       unitOfWork.SaveChanges();
    }
    transactionScope.Complete();
}
Run Code Online (Sandbox Code Playgroud)

显然,直接的答案是将所有更改整合到一个工作单元中,但这并不总是可能的,而且这也泄漏了Mongo DB的局限性。

我考虑过会话池,以便多个工作单元将使用同一会话,并在临时事务完成/中止时提交/回滚。

还有哪些其他解决方案?

澄清:

这里的问题专门涉及使用MongoDB 4.0(或更高版本)内置事务支持在MongoDB上实现工作单元。

Ami*_*shi 6

我从未使用过MongoDB;一无所知。我只是在回答TransactionScope; 所以不确定这是否对您有帮助。

请参考TransactionScope魔力。IMO,您应该寻找三个因素:

  1. 连接到数据库应该打开里面TransactionScope

    因此请记住,必须在TransactionScope块内打开该连接才能使其自动加入环境事务中。如果在此之前打开了连接,则它将不参与事务。

    不确定,但是看起来您可以使用手动注册在范围之外打开的连接connection.EnlistTransaction(Transaction.Current)

    查看您的评论和编辑,这不是问题。

  2. 所有操作应在同一线程上运行。

    所提供的环境事务TransactionScope是线程静态(TLS)变量。可以使用静态Transaction.Current属性进行访问。这是TransactionScopereferencesource.microsoft.com 上的代码。ThreadStatic ContextData,包含CurrentTransaction

    请记住,Transaction.Current是线程静态变量。如果您的代码在多线程环境中执行,则可能需要采取一些预防措施。必须参与环境事务的连接必须在创建管理该环境事务的TransactionScope的同一线程上打开。

    因此,所有操作应在同一线程上运行。

  3. 根据需要使用TransactionScopeOption(将其传递到的TransactionScope)构造函数值。

    TransactionScope通过该new语句实例化a时,事务管理器确定要参与的事务。确定后,作用域始终参与该事务。该决定基于两个因素:是否存在环境事务以及TransactionScopeOption构造函数中参数的值。

    我不确定您的代码应该做什么。您可以使用此枚举值。

如评论中所述,您正在使用async/await

最后,如果您在TransactionScope块内使用async / await,则应该知道它不能与TransactionScope一起很好地工作,并且您可能想研究.NET Framework 4.5.1中接受TransactionScopeAsyncFlowOption的新TransactionScope构造函数。TransactionScopeAsyncFlowOption.Enabled选项(不是默认选项)允许TransactionScope在异步继续中正常运行。

对于MongoDB,请查看这是否对您有帮助。