我正在使用“存储库+工作单元”模式在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();
}
}
}
因此,以下代码将无法工作。第一批数据将提前提交:
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的局限性。
我考虑过会话池,以便多个工作单元将使用同一会话,并在临时事务完成/中止时提交/回滚。
还有哪些其他解决方案呢?
说明:
这里的问题是关于使用MongoDB 4.0(或更高版本)内置事务支持在MongoDB上实现工作单元的。
答案 0 :(得分:6)
我从未使用过MongoDB;一无所知。我仅以TransactionScope
的方式回答;所以不确定是否会帮到您。
请参阅Magic Of TransactionScope。 IMO,您应该寻找三个因素:
应在TransactionScope
内 中打开与数据库的连接。
因此请记住,必须在TransactionScope块内打开连接才能使其自动加入环境事务中。如果在此之前打开了连接,则它将不参与事务。
不确定,但是看起来您可以manually enlist使用connection.EnlistTransaction(Transaction.Current)
在作用域外打开连接。
查看您的评论和编辑,这不是问题。
所有操作应在同一线程上运行。
TransactionScope
提供的环境事务是线程静态(TLS)变量。可以使用静态Transaction.Current
属性对其进行访问。这是referencesource.microsoft.com上的TransactionScope
代码。 ThreadStatic ContextData,包含CurrentTransaction
。
和
请记住,Transaction.Current是线程静态变量。如果您的代码在多线程环境中执行,则可能需要采取一些预防措施。必须参与环境事务的连接必须在创建用于管理该环境事务的TransactionScope的同一线程上打开。
因此,所有操作都应在同一线程上运行。
根据需要使用TransactionScopeOption
值(将其传递给TransactionScope
的构造函数)。
通过
TransactionScope
语句实例化new
时,事务管理器确定要参与的事务。确定后,作用域始终参与该事务。该决定基于两个因素:是否存在环境事务以及构造函数中TransactionScopeOption
参数的值。
我不确定您的代码应该做什么。您可以使用此枚举值。
如评论中所述,您正在使用async/await
。
最后,如果您在TransactionScope块内使用async / await,则应该知道它不能与TransactionScope很好地配合,并且您可能想研究.NET Framework 4.5.1中接受TransactionScopeAsyncFlowOption的新TransactionScope构造函数。 TransactionScopeAsyncFlowOption.Enabled选项(不是默认选项)使TransactionScope在异步继续中发挥良好的作用。
对于MongoDB,请查看this是否对您有所帮助。
答案 1 :(得分:1)
MongoDB驱动程序不了解周围的TransactionScopes。您需要手动征募他们,或者使用JohnKnoop.MongoRepository为您完成此任务:https://github.com/johnknoop/MongoRepository#transactions