回滚然后从队列中接收相同的消息
Rollback then receive the same message from queue
我有一个这样的激活存储过程:
DECLARE
@conversation_handle [uniqueidentifier],
@message_body [varbinary](max)
WHILE 1 = 1
BEGIN TRY
BEGIN TRANSACTION
WAITFOR
(
RECEIVE TOP (1)
@conversation_handle = [conversation_handle],
@message_body = [message_body]
FROM
[dbo].[my_queue]
), TIMEOUT 1000;
IF @@ROWCOUNT = 0
BEGIN
ROLLBACK TRANSACTION
BREAK
END
SAVE TRANSACTION SavePoint
-- do things
COMMIT TRANSACTION
END TRY
BEGIN CATCH
IF XACT_STATE() = 1
ROLLBACK TRANSACTION SavePoint
IF XACT_STATE() = -1
BEGIN
ROLLBACK TRANSACTION
BEGIN TRANSACTION;
RECEIVE TOP (1)
@message_body = [message_body]
FROM
[dbo].[my_queue]
WHERE
conversation_handle = @conversation_handle
END
-- insert the message to a error log table
END CONVERSATION @conversation_handle
COMMIT TRANSACTION
END CATCH
我的问题:如果这个队列有多个队列readers,在队列readerA回滚事务后,另一个队列readerB是否会收到毒消息,并且reader 鉴于所有消息都有自己的会话组,A 无法接收具有会话句柄的相同消息?
will another queue reader B receive the poison message after queue reader A has rolled the transaction back
是的。如果您回滚消息在队列中可用,等待另一个 reader 接收,并且您的会话组锁定被释放。
因此,如果您将一条消息从队列中取出并以注定失败的事务结束,或者 XACT_ABORT 开启,您别无选择,只能完全回滚。再加上与 MultipleActiveResultSets 的不兼容,保存点真的没那么有用。
那怎么办?一种选择是在队列上启用消息保留并提交 RECEIVE。然后在出错时写入您的错误 table。消息正文将在错误 table 和 SELECT 的对话生命周期中从队列中提供。
或者您可以将 MAX_QUEUE_READERS 设置为 1 以防止并发激活过程使毒消息出列。
或者(未经测试)您可以回滚,并在您的会话拥有独占 Application Lock 时重新接收毒消息,并要求激活过程的初始接收在同一资源名称上持有共享锁。
我有一个这样的激活存储过程:
DECLARE
@conversation_handle [uniqueidentifier],
@message_body [varbinary](max)
WHILE 1 = 1
BEGIN TRY
BEGIN TRANSACTION
WAITFOR
(
RECEIVE TOP (1)
@conversation_handle = [conversation_handle],
@message_body = [message_body]
FROM
[dbo].[my_queue]
), TIMEOUT 1000;
IF @@ROWCOUNT = 0
BEGIN
ROLLBACK TRANSACTION
BREAK
END
SAVE TRANSACTION SavePoint
-- do things
COMMIT TRANSACTION
END TRY
BEGIN CATCH
IF XACT_STATE() = 1
ROLLBACK TRANSACTION SavePoint
IF XACT_STATE() = -1
BEGIN
ROLLBACK TRANSACTION
BEGIN TRANSACTION;
RECEIVE TOP (1)
@message_body = [message_body]
FROM
[dbo].[my_queue]
WHERE
conversation_handle = @conversation_handle
END
-- insert the message to a error log table
END CONVERSATION @conversation_handle
COMMIT TRANSACTION
END CATCH
我的问题:如果这个队列有多个队列readers,在队列readerA回滚事务后,另一个队列readerB是否会收到毒消息,并且reader 鉴于所有消息都有自己的会话组,A 无法接收具有会话句柄的相同消息?
will another queue reader B receive the poison message after queue reader A has rolled the transaction back
是的。如果您回滚消息在队列中可用,等待另一个 reader 接收,并且您的会话组锁定被释放。
因此,如果您将一条消息从队列中取出并以注定失败的事务结束,或者 XACT_ABORT 开启,您别无选择,只能完全回滚。再加上与 MultipleActiveResultSets 的不兼容,保存点真的没那么有用。
那怎么办?一种选择是在队列上启用消息保留并提交 RECEIVE。然后在出错时写入您的错误 table。消息正文将在错误 table 和 SELECT 的对话生命周期中从队列中提供。
或者您可以将 MAX_QUEUE_READERS 设置为 1 以防止并发激活过程使毒消息出列。
或者(未经测试)您可以回滚,并在您的会话拥有独占 Application Lock 时重新接收毒消息,并要求激活过程的初始接收在同一资源名称上持有共享锁。