MongoDB的存储库模式-一项事务可处理多个工作单元 [英] Repository pattern with MongoDB - multiple units of work with one transaction

查看:211
本文介绍了MongoDB的存储库模式-一项事务可处理多个工作单元的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I'm implementing a DAL abstraction layer on top of the C# Mongo DB driver using the Repository + Unit of Work pattern. My current design is that every unit of work instance opens (and closes) a new Mongo DB session. The problem is that Mongo DB only allows a 1:1 ratio between a session and a transaction, so multiple units of work under the same .NET transaction will not be possible.

当前实现为:

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();
       }
    }
}

因此,以下代码将无法工作.第一批数据将提前提交:

And because of this, the following code won't work. The first batch of data will be committed ahead of time:

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();
}

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

Obviously the immediate answer would be to bring all of the changes into one unit of work, but it's not always possible, and also this leaks the Mongo DB limitation.

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

I thought about session pooling, so that multiple units of work will use the same session, and commit/rollback when the transient transaction completes/aborts.

还有哪些其他解决方案呢?

What other solutions are possible?

说明:

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

The question here is specifically regarding Unit-Of-Work implementation over MongoDB using the MongoDB 4.0 (or later) built-in transaction support.

推荐答案

我从没使用过MongoDB;对此一无所知.我只是用TransactionScope来回答;所以不确定是否能帮到您.

I never used MongoDB; do not know anything about it. I am only answering in terms of TransactionScope; so not sure if this will help you.

请参考 Magic Of TransactionScope . IMO,您应该寻找三个因素:

Please refer the Magic Of TransactionScope. IMO, there are three factors you should look for:

  1. 应在

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

    So remember, the connection must be opened inside the TransactionScope block for it to enlist in the ambient transaction automatically. If the connection was opened before that, it will not participate in the transaction.

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

    Not sure but it looks that you can manually enlist the connection opened outside the scope using connection.EnlistTransaction(Transaction.Current).

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

    Looking at your comment and the edit, this is not an issue.

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

    All operations should run on same thread.

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

    The ambient transaction provided by the TransactionScope is a thread-static (TLS) variable. It can be accessed with static Transaction.Current property. Here is the TransactionScope code at referencesource.microsoft.com. ThreadStatic ContextData, contains the CurrentTransaction.

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

    Remember that Transaction.Current is a thread static variable. If your code is executing in a multi-threaded environments, you may need to take some precautions. The connections that need to participate in ambient transactions must be opened on the same thread that creates the TransactionScope that is managing that ambient transaction.

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

    So, all the operations should run on same thread.

    使用 TransactionScopeOption (将其传递给TransactionScope的构造函数)值.

    Play with TransactionScopeOption (pass it to constructor of TransactionScope) values as per your need.

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

    Upon instantiating a TransactionScope by the new statement, the transaction manager determines which transaction to participate in. Once determined, the scope always participates in that transaction. The decision is based on two factors: whether an ambient transaction is present and the value of the TransactionScopeOption parameter in the constructor.

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

    I am not sure what your code expected to do. You may play with this enum values.

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

    As you mentioned in the comment, you are using async/await.

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

    Lastly, if you are using async/await inside the TransactionScope block, you should know that it does not work well with TransactionScope and you might want to look into new TransactionScope constructor in .NET Framework 4.5.1 that accepts a TransactionScopeAsyncFlowOption. TransactionScopeAsyncFlowOption.Enabled option, which is not the default, allows TransactionScope to play well with asynchronous continuations.

    对于MongoDB,请查看是否对您有所帮助.

    For MongoDB, see if this helps you.

    这篇关于MongoDB的存储库模式-一项事务可处理多个工作单元的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆