0

我有一个使用 NServiceBus 的消息处理程序,它需要在两个不同的数据库上执行 SQL 代码。连接字符串具有不同的初始目录,但在其他方面相同。

当消息被拾取时,第一个 sql 连接成功打开,但第二个 sql 连接导致调用 .Open 时抛出以下异常。

分布式事务管理器 (MSDTC) 的网络访问已被禁用。请使用组件服务管理工具在 MSDTC 的安全配置中启用 DTC 以进行网络访问。

我们不使用 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 依次打开多个连接是否需要额外配置?

4

2 回答 2

0

默认情况下,NServiceBus 将每个消息处理程序包装在一个事务中,这会导致对同一消息处理程序内的不同数据库连接的查询失败,除非启用了 MSDTC。

我可以使用 BusConfiguration.Transactions().DoNotWrapHandlersExecutionInATransactionScope() 禁用它

于 2018-08-16T22:08:25.597 回答
0

您可以在NServiceBus 文档中找到有关事务的更多信息。

这不仅仅与 NServiceBus 相关,我们只是提供连接到传输(如 MSMQ、Azure 服务总线等)、持久化器和您自己的数据库的不同方式。

但是即使没有 NServiceBus,当连接到两个数据库时,你要么需要一个分布式事务,要么确保事务没有升级为分布式事务。问题是,如果没有分布式事务,当一个事务成功提交时,另一个事务可能会失败。结果是您的两个数据库不再同步或一致。

如果在DatabaseA 中存储了订单,在DatabaseB 中跟踪库存,您可能会从库存中扣除1,但由于交易失败,订单可能永远不会被存储。您需要在没有分布式事务的情况下自己补偿这一点。

这并不是说分布式事务总是要走的路。您可能没有使用它们,因为您的 DBA 不喜欢它们。MSDTC 始终将可序列化事务放在您的数据上,这些事务具有最重的锁。保持它们打开的时间越长,需要等待的并发运行的事务就越多。您的软件可能存在巨大的性能问题。

另一方面,创建补偿交易可能非常非常困难。想想 DatabaseA 可能会失败,DatabaseB 可能会成功的事实。但是消息会发生什么?它从队列中消失了吗?还是会留在队列中并再次处理?重复数据的可能结果,DatabaseB 会再次成功吗?

幸运的是,您已经在使用 NServiceBus。您可能想查看可以帮助解决其中一些问题的发件箱功能。

于 2018-08-17T10:38:29.733 回答