Jul*_*anR 10 c# msdtc transactionscope sql-server-2012 rebus
当我们需要在我们的应用程序中进行数据库访问时,我们使用以下模式:
CreateOpenConnection只能执行new SqlConnection(myConnectionString)并调用Open()它.在我们执行查询之前调用此方法,并在查询返回后处理连接.work.Commit()如下所示:work.Commit:
using (var tranScope = new TransactionScope(TransactionScopeOption.RequiresNew))
{
using (var conn = DapperFactory.CreateOpenConnection())
{
var count = _changeTracker.CommitChanges(conn);
tranScope.Complete();
return count;
}
}
Run Code Online (Sandbox Code Playgroud)
这似乎非常适合作为Web服务的一部分进行一般使用,但是当我尝试将其与Rebus结合使用时,它正在给我MSDTC带来麻烦.
从我可以告诉,卤面(当它在队列中处理消息)创建一个新的TransactionScope,以便在故障处理消息的情况下,东西可以回滚.现在,到目前为止,这本身一直很好.我可以SqlConnection在没有任何问题的情况下在Rebus消息处理程序中打开一个新的内容(但是,在同一个Rebus 中使用我们的遗留实体框架查询和手动SqlConnections TransactionScope不起作用,但我现在不认为这是一个问题).但昨天我问了以下问题:
答案似乎是使用Rebus的传奇功能.我尝试实现它并配置它,以便Rebus saga持久化到新的SQL Server数据库(具有不同的连接字符串).据推测,使用该SQL Server持久性打开SqlConnection它自己的,因为每当我尝试创建一个SqlConnection现在,我得到以下异常:
已禁用分布式事务管理器(MSDTC)的网络访问.请使用组件服务管理工具在MSDTC的安全配置中启用DTC以进行网络访问.
在配置和性能开销方面,我非常非常希望避免使用MSDTC .我可能错了,但它似乎也没有必要.
我认为这里发生的事情是Rebus创建了一个环境TransactionScope,并且SqlConnection它创建了该范围的enlists.当我尝试创建自己的内容时,SqlConnection它也会尝试登记到该环境范围,并且因为涉及多个连接,它会被提升为MSDTC,但这会失败.
我知道如何解决这个问题,但我不知道这是否正确.我会做的是:
Enlist=false到我的应用程序的连接字符串,以便它永远不会访问环境事务.Commit方法,以便它不会创建一个新的TransactionScope(我的连接将不再订阅,因为我只是告诉它不应该),但它使用conn.BeginTransaction.像这样:
var transaction = conn.BeginTransaction();
try
{
var count = _changeTracker.CommitChanges(conn);
transaction.Commit();
return count;
}
catch
{
transaction.Rollback();
throw;
}
finally
{
transaction.Dispose();
}
Run Code Online (Sandbox Code Playgroud)
我只是不确定这是否是正确的方法以及可能存在的缺点.
有小费吗?
更新:澄清一下,并不是work.Commit()那些给我带来问题的,我很确定它会起作用,但我从来没有到达那里因为我的查询失败了.
失败的一个例子:
public int? GetWarehouseID(int appID)
{
var query = @"
select top 1 ID from OrganizationUnits o
where TypeID & 16 = 16 /* warehouse */";
using (var conn = _dapper.OpenConnection())
{
var id = conn.Query<int?>(query).FirstOrDefault();
return id;
}
}
Run Code Online (Sandbox Code Playgroud)
当TransactionScopeRebus创建了一个,以及在SqlConnectionRebus打开之后,它会被调用.打开我的时候 SqlConnection,它会尝试登记并崩溃
我对您看到这一点感到有些惊讶,因为这RequiresNew 应该意味着它与其他事务隔离;通常,此消息意味着在事务范围内已激活 2 个连接 - 您确定没有其他代码在该块内创建/打开连接吗?
您提出的解决方案应该有效 - 尽管在某些方面TransactionScopeOption.Suppress可能比更改配置更方便(但两者都应该有效)。但是,存在一个问题:ADO.NET 事务必须传递给各个命令,因此您需要(还需要稍微整理一下代码):
using(var transaction = conn.BeginTransaction()) {
try {
var count = _changeTracker.CommitChanges(conn, transaction);
transaction.Commit();
return count;
} catch {
transaction.Rollback();
throw;
}
}
Run Code Online (Sandbox Code Playgroud)
whereCommitChanges接受交易 - 可能使用可选参数:
int CommitChanges(DbConnection connection, DbTransaction transaction = null)
{ ... }
Run Code Online (Sandbox Code Playgroud)
您的命名表明DapperFactory您正在使用“dapper” - 在这种情况下,您可以将其传递给“dapper”,无论它是否为空,即
conn.Execute(sql, args, transaction: transaction);
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
3904 次 |
| 最近记录: |