我有一个使用NServiceBus的消息处理程序,该消息处理程序需要在两个不同的数据库上执行SQL代码。连接字符串的初始目录不同,但其他方面相同。
收到消息后,第一个sql连接成功打开,但是第二个sql连接导致在调用.Open时引发以下异常。
分布式事务管理器(MSDTC)的网络访问已得到 禁用的。请在安全性中启用DTC进行网络访问 使用组件服务管理为MSDTC配置 工具。
我们不使用MSDTC。
这是失败的代码。它将在connB.Open()
上失败public void Handle(MyMsgCmd message)
{
using (SqlConnection connA = new SqlConnection(myConnectionStringA))
{
connA.Open();
}
using (SqlConnection connB = new SqlConnection(myConnectionStringB))
{
connB.Open();
}
}
从命令行应用程序或Web应用程序运行时,相同的代码也可以很好地工作。仅当从NServiceBus调用该异常时,才会引发该异常。
这些连接中的每一个在第一次打开或单独打开时都将成功打开,但是只要存在第二个连接,即使已知良好,第二个连接也将始终无法打开。
是否需要其他配置才能与NServiceBus依次打开多个连接?
答案 0 :(得分:0)
默认情况下,NServiceBus看起来将每个消息处理程序包装在事务中,并且除非启用了MSDTC,否则导致对同一消息处理程序内不同数据库连接的查询失败。
我可以使用BusConfiguration.Transactions()。DoNotWrapHandlersExecutionInATransactionScope()禁用该功能
答案 1 :(得分:0)
您可以在NServiceBus documentation中找到有关交易的更多信息。
这不仅与NServiceBus有关,我们只是提供了不同的连接传输方式(例如MSMQ,Azure Service Bus等),持久性和您自己的数据库的方式。
但是,即使没有NServiceBus,在连接到两个数据库时,您也需要分布式事务,或者确保事务未升级为分布式事务。问题是,如果没有分布式事务,则当一个事务成功提交时,另一事务可能会失败。结果您的两个数据库不再同步或不一致。
如果在DatabaseA中存储了订单,并且在DatabaseB中跟踪了库存,则可以从库存中扣除1,但是由于交易失败,该订单可能永远不会存储。您需要自己补偿而无需进行分布式交易。
不要说分布式事务始终是必经之路。您可能没有使用它们,因为您的DBA不喜欢它们。 MSDTC始终在您的数据上放置可序列化的事务,这些事务具有最重的锁。打开它们的时间越长,需要等待的并发运行的事务越多。您的软件中可能存在巨大的性能问题。
另一方面,创建补偿交易可能非常非常困难。考虑一下数据库A可能失败,数据库B可能成功的事实。但是消息发生了什么?它从队列中消失了吗?还是将其保留在队列中并再次处理?数据重复的可能结果是DatabaseB是否再次成功?
幸运的是,您已经在使用NServiceBus。您可能想看看Outbox feature可以帮助解决其中一些问题。