我爲兩個存儲過程設置了內部激活。一個插入一個或多個記錄,另一個記錄更新同一個表中的一個或多個記錄。所以,我有兩個發起者,兩個目標隊列。 到目前爲止,它在開發中工作正常,但我不知道當我們將它移動到prod中經常調用這兩個存儲過程時,可能會遇到什麼類型的問題。我們已經遇到了由這兩個存儲過程導致的死鎖問題。異步執行是這個實現的主要目標。SQL Service Broker內部激活問題
問題:
有沒有辦法使用一個目標隊列的存儲程序,以防止死鎖的任何機會的方法嗎?
有什麼我可以做的,讓它更可靠嗎?像一個執行錯誤不應該阻止傳入請求 到隊列?
提高可伸縮性的提示(每秒執行次數很多)?
如果存在死鎖,我可以設置RETRY嗎?
這裏是插入存儲過程的部分代碼;
CREATE QUEUE [RecordAddUsersQueue];
CREATE SERVICE [RecordAddUsersService] ON QUEUE [RecordAddUsersQueue];
ALTER QUEUE [AddUsersQueue] WITH ACTIVATION
( STATUS = ON,
MAX_QUEUE_READERS = 1, --or 10?
PROCEDURE_NAME = usp_AddInstanceUsers,
EXECUTE AS OWNER);
CREATE PROCEDURE [dbo].[usp_AddInstanceUsers] @UsersXml xml
AS
BEGIN
DECLARE @Handle uniqueidentifier;
BEGIN DIALOG CONVERSATION @Handle
FROM SERVICE [RecordAddUsersService]
TO SERVICE 'AddUsersService'
ON CONTRACT [AddUsersContract]
WITH ENCRYPTION = OFF;
SEND ON CONVERSATION @Handle
MESSAGE TYPE [AddUsersXML] (@UsersXml);
END
GO
CREATE PROCEDURE [dbo].[usp_SB_AddInstanceUsers]
AS
BEGIN
DECLARE @Handle uniqueidentifier;
DECLARE @MessageType sysname;
DECLARE @UsersXML xml;
WHILE (1 = 1)
BEGIN
BEGIN TRANSACTION;
WAITFOR
(RECEIVE TOP (1)
@Handle = conversation_handle,
@MessageType = message_type_name,
@UsersXML = message_body
FROM [AddUsersQueue]), TIMEOUT 5000;
IF (@@ROWCOUNT = 0)
BEGIN
ROLLBACK TRANSACTION;
BREAK;
END
IF (@MessageType = 'ReqAddUsersXML')
BEGIN
--<INSERT>....
DECLARE @ReplyMsg nvarchar(100);
SELECT
@ReplyMsg = N'<ReplyMsg>Message for AddUsers Initiator service.</ReplyMsg>';
SEND ON CONVERSATION @Handle
MESSAGE TYPE [RepAddUsersXML] (@ReplyMsg);
END
ELSE
IF @MessageType = N'http://schemas.microsoft.com/SQL/ServiceBroker/EndDialog'
BEGIN
END CONVERSATION @Handle;
END
ELSE
IF @MessageType = N'http://schemas.microsoft.com/SQL/ServiceBroker/Error'
BEGIN
END CONVERSATION @Handle;
END
COMMIT TRANSACTION;
END
END
GO
謝謝
Kuzey
_「然後激活的過程應執行添加邏輯或更新邏輯,具體取決於消息類型。」_合併插入和更新存儲過程將需要在應用程序端進行重大更改。如果該應用仍然會調用插入和更新sprocs,但是這兩個sprocs會調用第三個sproc,這將是新的激活sproc,具有不同的參數/ message_types? – Binsel
我不知道你的代碼,但通常應該是一個簡單的過程。今天你有兩個過程,每個過程都有一個塊'IF @messageType ='someType'BEGIN END'。您將簡單合併IF,例如'IF @messageType ='someType'BEGIN END IF @messageType ='otherType'BEGIN END' –
使處理句柄「TOP(1000)」更加複雜,但並不多。也是一個直接的,機械的變革。在遊標循環內部接收到@table,打開遊標,然後應用與之前一樣的邏輯(IF @message Type ...)。必須小心,不要過早提交,必須在提交之前處理@table中的所有消息,否則您有可能在發生錯誤時丟失消息。 –