0

我正在使用 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触发器中的部分。

很长一段时间以来,我一直对此感到震惊。拜托,有人可以帮我解决这个问题吗

4

1 回答 1

3

您需要RECEIVEmessage_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已经工作的方式(使用外部激活除外)。

于 2012-10-02T08:21:04.347 回答