gpt4 book ai didi

c# - SqlConnection 并避免升级到 MSDTC

转载 作者:可可西里 更新时间:2023-11-01 09:13:45 26 4
gpt4 key购买 nike

当我们需要在我们的应用程序中进行数据库访问时,我们使用以下模式:

  • 为了查询,我们有一个带有方法 CreateOpenConnection 的静态工厂类这只不过是 new SqlConnection(myConnectionString)并调用 Open()在上面。在我们执行查询之前调用此方法,并在查询返回后释放连接。
  • 对于插入/更新/删除,我们使用工作单元模式,在这种模式下,更改被分批处理并通过调用 work.Commit() 提交到数据库。像这样:

工作.提交:

using (var tranScope = new TransactionScope(TransactionScopeOption.RequiresNew))
{
using (var conn = DapperFactory.CreateOpenConnection())
{
var count = _changeTracker.CommitChanges(conn);

tranScope.Complete();

return count;
}
}

这似乎非常适合作为 Web 服务的一部分的一般用途,但是当我尝试将它与 Rebus 结合使用时,目前给我带来了 MSDTC 麻烦。

据我所知,Rebus(当它处理队列中的消息时)创建了一个新的 TransactionScope这样在处理消息失败的情况下,可以回滚内容。现在,到目前为止,这本身运行良好。我可以打开一个新的 SqlConnection在 Rebus 消息处理程序中没有任何问题(但是,在同一个 Rebus TransactionScope 中使用我们遗留的 Entity Framework 查询手动 SqlConnections 不起作用,但我现在不认为这是一个问题).但是昨天我问了以下问题:

Serial processing of a certain message type in Rebus

答案似乎是使用 Rebus 的 saga 特性。我尝试实现它并对其进行配置,以便将 Rebus saga 持久保存到新的 SQL Server 数据库(具有不同的连接字符串)。据推测,使用该 SQL Server 持久性会打开一个 SqlConnection它自己的,因为任何时候我尝试创建一个 SqlConnection现在,我得到以下异常:

Network access for Distributed Transaction Manager (MSDTC) has been disabled. Please enable DTC for network access in the security configuration for MSDTC using the Component Services Administrative tool.

考虑到配置和性能开销,启用 MSDTC 是我非常非常想避免的事情。我可能是错的,但这似乎也没有必要。

我推测这里发生的是 Rebus 创建了一个环境 TransactionScopeSqlConnection它创建了该范围的登记。当我尝试创建自己的 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();
}

我只是不确定这是否是正确的方法以及可能的缺点是什么。

有什么建议吗?

更新:澄清一下,这不是 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;
}
}

这会在 TransactionScope 时被调用由 Rebus 以及在 SqlConnection 之后创建由 Rebus 打开。打开我的 SqlConnection ,它尝试征募并崩溃

最佳答案

您看到这个我有点惊讶,因为 RequiresNew 应该 意味着它与其他事务隔离;通常,此消息意味着在事务范围内已激活 2 个连接 - 您确定没有其他代码在该 block 内创建/打开连接吗?

您提出的解决方案应该可行 - 虽然在某些方面 TransactionScopeOption.Suppress 可能比更改您的配置更方便(但两者都应该可行)。但是,存在一个问题:ADO.NET 事务必须传递给各个命令,因此您需要(也稍微​​整理一下代码):

using(var transaction = conn.BeginTransaction()) {
try {
var count = _changeTracker.CommitChanges(conn, transaction);
transaction.Commit();
return count;
} catch {
transaction.Rollback();
throw;
}
}

其中 CommitChanges 接受交易 - 可能使用可选参数:

int CommitChanges(DbConnection connection, DbTransaction transaction = null)
{ ... }

DapperFactory 的命名表明您使用的是“dapper”——在这种情况下,无论它是否为 null,您都可以将其传递给“dapper”,即

conn.Execute(sql, args, transaction: transaction);

关于c# - SqlConnection 并避免升级到 MSDTC,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16854500/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com