具有自定义 sqlconnection 的 NServicebus 处理程序

NServicebus handler with custom sqlconnection

我有一个 NServiceBus 处理程序,它创建一个新的 sql 连接和新的 sql 命令。

但是,执行的命令直到整个过程完成后才提交到数据库。

好像处理程序本身有一个隐藏的sql事务。

我将我的代码移动到没有 nservicebus 的自定义控制台应用程序中,sql 命令立即执行并保存。不像在 nservicebus 中它直到处理程序结束才保存。

找到解决方案。

在我的连接字符串中,我必须添加 Enlist=False

确实每个handler都包裹在一个transaction中,默认的transaction保证依赖于DTC。那是故意的:)

如果禁用它,您可能会收到重复的消息或丢失一些数据,因此必须小心谨慎。您可以使用端点配置禁用事务 API 而不是使用连接字符串中的选项。

在这里您可以找到有关配置和可用保证的更多信息http://docs.particular.net/nservicebus/transports/transactions

如@wlabaj 所述,设置 Enlist=False 确实会确保在处理程序中打开的事务不同于传输到 receive/send 消息所使用的事务。

但是请务必注意,它会更改消息处理语义。默认情况下,当使用 DTC 时,receive/send 和处理程序内的任何事务操作都将是 commited/rolled-back 原子的。使用 Enlist=False 时情况并非如此,因此可能会为同一消息提交多个处理程序事务。考虑以下场景作为可能发生的示例:

  • 收到消息(传输交易开始)
  • 消息在处理程序中成功处理(处理程序事务成功提交)
  • 传输事务失败,消息被移回输入队列
  • 第二次收到消息
  • 消息在处理程序中成功处理
  • ...

Enlist-False 设置的行为在您的案例中可能是理想的行为。话虽如此,我认为有必要澄清一下消息处理语义的后果。

工作单元

消息应作为单个工作单元处理。要么一切成功,要么失败。

如果您想执行多个工作单元,那么

  • 创建多个端点
  • 或发送多条消息

这还有一个好处,即可以并行处理这些内容。

请注意,创建多个处理程序不会产生这种效果。同一端点上的所有处理程序将属于同一工作单元,即事务。

立即发货

如果你真的想发送一个特定的消息,而消息的发送不能是工作单元的一部分,那么你可以像这样立即发送:

using (new TransactionScope(TransactionScopeOption.Suppress))
{
    var myMessage = new MyMessage();
    bus.Send(myMessage);
}

V5有效,其他版本最好看文档:

http://docs.particular.net/nservicebus/messaging/send-a-message#dispatching-a-message-immediately

征募=假

这是一种解决方法,不得用于规避特定的事务配置,Tomasz 对此进行了很好的解释。

这可能会导致数据损坏,因为在错误恢复的情况下可以多次处理同一消息,然后将再次执行相同的数据库操作。