我正在使用SQL代理执行一些异步任务(在我的情况下发送邮件)。但我遇到的问题是每次将XML消息从触发器传递到队列时,将值插入队列时运行的存储过程将运行两次。
我有一个消息类型:
CREATE MESSAGE TYPE MailMessage
AUTHORIZATION dbo
VALIDATION = WELL_FORMED_XML
我有合同:
CREATE CONTRACT MailContract
AUTHORIZATION dbo
(MailMessage SENT BY INITIATOR)
我有一个队列:
CREATE QUEUE dbo.MessageQueue
WITH STATUS=ON,
ACTIVATION (
PROCEDURE_NAME = MailExecuter ,
MAX_QUEUE_READERS = 1,
EXECUTE AS OWNER );
我有两项服务:
CREATE SERVICE MailSendActivator
AUTHORIZATION dbo
ON QUEUE dbo.MessageQueue (MailContract) ; // I have removed this the contract to make it a initiator but it did not worked out
-- Create target Service
CREATE SERVICE MailSendExec
AUTHORIZATION dbo
ON QUEUE dbo.MessageQueue (MailContract);
这是我的触发器:
CREATE TRIGGER MailSendTrigOnMailQueue ON dbo.MailQueue
FOR INSERT
As
SET NOCOUNT ON;
DECLARE @MessageBody XML
DECLARE @TableId int
SET @MessageBody = (SELECT CreatedDateTime,[Subject], MailType FROM inserted
FOR XML AUTO)
If (@MessageBody IS NOT NULL)
BEGIN
DECLARE @Handle UNIQUEIDENTIFIER;
BEGIN DIALOG CONVERSATION @Handle
FROM SERVICE MailSendActivator
TO SERVICE 'MailSendExec'
ON CONTRACT MailContract
WITH ENCRYPTION = OFF;
SEND ON CONVERSATION @Handle MESSAGE TYPE MailMessage(@MessageBody);
END
我有一个存储过程: 在存储过程中,我将值插入测试表是否存储过程正在运行。
存储过程:
CREATE PROCEDURE dbo.MailExecuter
AS
BEGIN
DECLARE @msgBody XML
DECLARE @dlgId uniqueidentifier
Insert into TestTable(Name, Test) values('MEX','test');
WHILE (1 = 1)
BEGIN
WAITFOR ( RECEIVE TOP(1) @msgBody = CAST(message_body AS XML), @dlgId = conversation_handle FROM dbo.MessageQueue ), TIMEOUT 500
IF (@@ROWCOUNT = 0 OR @msgBody IS NULL)
BEGIN
BREAK
END
ELSE
BEGIN
DECLARE @Subject nvarchar(200), @CreatedDateTime datetime, @MailType nvarchar(50)
---EXEC dbo.SendMails 1,1;
END
END CONVERSATION @dlgId
END
END
但是存储过程运行了两次并填充了我的测试表两次。我认为问题在于触发器中的send conversation
部分。
我很长时间都对此深恶痛绝。拜托,有人可以帮助我吗
答案 0 :(得分:3)
您需要在RECEIVE
投影列表中添加message_type_name
。当消息类型为MailMessage
时,您必须查看收到的消息类型,仅调用邮件例程。事实上,您将始终收到第二条消息,即END DIALOG
中的消息。你只需要在那种情况下再次调用END DIALOG,关闭发送方句柄:
WAITFOR (
RECEIVE TOP(1)
@msgBody = CAST(message_body AS XML),
@dlgId = conversation_handle ,
@msgType = message_type_name
FROM dbo.MessageQueue ), TIMEOUT 500
IF (@@ROWCOUNT = 0 OR @msgBody IS NULL)
BREAK
ELSE IF @msgType = N'MailMessage'
BEGIN
DECLARE @Subject nvarchar(200), @CreatedDateTime datetime, @MailType nvarchar(50)
---EXEC dbo.SendMails 1,1;
END
END CONVERSATION @dlgId;
你重新发明轮子有什么特别的原因吗?这几乎就是sp_send_dbmail
已经有效的方法(除了使用外部激活)。