c# - MongoDB 的存储库模式 - 一个事务的多个工作单元
问题描述
我正在使用 Repository + Unit of Work 模式在 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 上实现工作单元的具体问题。
解决方案
我从未使用过 MongoDB;对此一无所知。我只是在回答TransactionScope
; 所以不确定这是否会对您有所帮助。
请参考TransactionScope 的魔法。IMO,您应该寻找三个因素:
与数据库的连接应在
TransactionScope
.所以请记住,必须在 TransactionScope 块内打开连接才能自动加入环境事务。如果在此之前打开了连接,它将不参与事务。
不确定,但看起来您可以使用
connection.EnlistTransaction(Transaction.Current)
.查看您的评论和编辑,这不是问题。
所有操作都应该在同一个线程上运行。
提供的环境事务
TransactionScope
是线程静态 (TLS) 变量。可以使用静态Transaction.Current
属性访问它。这是TransactionScope
referencesource.microsoft.com 上的代码。ThreadStatic ContextData,包含CurrentTransaction
.和
请记住 Transaction.Current 是一个线程静态变量。如果您的代码在多线程环境中执行,您可能需要采取一些预防措施。需要参与环境事务的连接必须在创建管理该环境事务的 TransactionScope 的同一线程上打开。
因此,所有操作都应该在同一个线程上运行。
根据您的需要使用
TransactionScopeOption
(将其传递给的构造函数TransactionScope
)值。TransactionScope
在通过语句实例化 a时new
,事务管理器确定要参与哪个事务。一旦确定,范围始终参与该事务。该决定基于两个因素:环境事务是否存在以及TransactionScopeOption
构造函数中的参数值。我不确定您的代码预期会做什么。您可以使用此枚举值。
正如您在评论中提到的,您正在使用async/await
.
最后,如果您在 TransactionScope 块中使用 async/await,您应该知道它不适用于 TransactionScope,您可能需要查看 .NET Framework 4.5.1 中接受 TransactionScopeAsyncFlowOption 的新 TransactionScope 构造函数。TransactionScopeAsyncFlowOption.Enabled 选项不是默认选项,它允许 TransactionScope 与异步延续很好地配合。
对于 MongoDB,看看这是否对您有帮助。
推荐阅读
- javascript - 当它们都具有相同的 CSS 类时,如何一个接一个地单击页面上的所有按钮(开发控制台脚本)
- go - 堆栈跟踪和 golang 错误。Unwrap()
- javascript - 带有 webpack 3 的摩纳哥编辑器 - 意外令牌 {
- python - 在哪里合并 goup 以正确导出 json?
- javascript - 如何根据下拉列表中的选择显示表格值?
- spring-cloud-stream - 在 Spring Cloud Data Flow 中更改流中的实例数无效
- python - 在子进程中运行和停止脚本
- java - 使用 Gremlin Query 的 Union 方法及其对 Neptune Transactions 的影响
- node.js - 如何使用nodejs 10x在aws lambda中将发布请求发送到外部api?
- c++ - 我应该使用 const shared_ptr
& 或 shared_ptr 作为我的 lambda 函数的参数?