具有自定义 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 对此进行了很好的解释。
这可能会导致数据损坏,因为在错误恢复的情况下可以多次处理同一消息,然后将再次执行相同的数据库操作。
我有一个 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 对此进行了很好的解释。
这可能会导致数据损坏,因为在错误恢复的情况下可以多次处理同一消息,然后将再次执行相同的数据库操作。