我正在使用Repository + Unit of Work模式在C#Mongo DB驱动程序之上实现DAL抽象层。我目前的设计是每个工作单元实例打开(并关闭)一个新的Mongo数据库会话。问题是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上的工作单元实现。
我从未使用过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是否可以帮助您。