2014-01-15 410 views
1

我有一個程序(usp_LoadCDRActivated),它調用另一個程序(usp_crs_LoadCDRsByBatch)。 proc usp_crs_LoadCDRsByBatch調用另外六個過程,將數據從單個臨時表加載到其他彙總表。我通過隊列運行父進程(usp_LoadCDRActivated)。處理死鎖

現在,當我啓動隊列時,始終存在死鎖,因此會自動禁用隊列的異常。

請幫我解決問題。

如果您想了解更多詳細信息,請告訴我。

下面是父處理...

ALTER procedure [dbo].[usp_LoadCDRActivated]  
as  
begin  
set nocount on;  
declare @h uniqueidentifier  
     , @messageTypeName sysname  
     , @messageBody varbinary(max)  
     , @xmlBody xml  
     , @batchID int  
     , @startTime datetime  
     , @finishTime datetime  
     , @execErrorNumber int  
     , @execErrorMessage nvarchar(2048)  
     , @xactState smallint  
     , @token uniqueidentifier;  

begin transaction;  
begin try;  
    receive top(1)  
       @h = [conversation_handle]  
       , @messageTypeName = [message_type_name]  
       , @messageBody = [message_body]  
    from [LoadCDRQueue];  
    if (@h is not null)  
     begin  
      if (@messageTypeName = N'DEFAULT')  
       begin  
        -- The DEFAULT message type is a procedure invocation.  
        -- Extract the name of the procedure from the message body.  
        --  
        select @xmlBody = CAST(@messageBody as xml);  
        select @batchID = @xmlBody.value(  
                 '(//batch/batchID)[1]'  
                 , 'int' 
                );  

        save transaction usp_LoadCDR_procedure;  
        select @startTime = GETUTCDATE();  
        begin try  
         exec usp_crs_LoadCDRsByBatch @batchID;  
        end try  
        begin catch  
         -- This catch block tries to deal with failures of the procedure execution  
         -- If possible it rolls back to the savepoint created earlier, allowing  
         -- the activated procedure to continue. If the executed procedure  
         -- raises an error with severity 16 or higher, it will doom the transaction  
         -- and thus rollback the RECEIVE. Such case will be a poison message,  
         -- resulting in the queue disabling.  
         --  
         select @execErrorNumber = ERROR_NUMBER(),  
           @execErrorMessage = ERROR_MESSAGE(),  
           @xactState = XACT_STATE();  
         if (@xactState = -1)  
          begin  
           rollback;  
           raiserror(N'Unrecoverable error in procedure usp_crs_LoadCDRsByBatch (%i): %i: %s', 16, 10,  
           @batchID, @execErrorNumber, @execErrorMessage);  
          end  
         else if (@xactState = 1)  
          begin  
           rollback transaction usp_LoadCDR_procedure;  
          end  
        end catch  

        select @finishTime = GETUTCDATE();  
        select @token = [conversation_id]  
        from sys.conversation_endpoints  
        where [conversation_handle] = @h;  
        if (@token is null)  
         begin  
          raiserror(N'Internal consistency error: conversation not found', 16, 20);  
         end  
        update [LoadCDRResults] set  
        [start_time] = @starttime  
        , [finish_time] = @finishTime  
        , [error_number] = @execErrorNumber  
        , [error_message] = @execErrorMessage  
        where [token] = @token;  
        if (0 = @@ROWCOUNT)  
         begin  
          raiserror(N'Internal consistency error: token not found', 16, 30);  
         end  
        end conversation @h;  
       end  
else if (@messageTypeName = N'http://schemas.microsoft.com/SQL/ServiceBroker/EndDialog')  
begin  
end conversation @h;  
end  
else if (@messageTypeName = N'http://schemas.microsoft.com/SQL/ServiceBroker/Error')  
begin  
declare @errorNumber int  
, @errorMessage nvarchar(4000);  
select @xmlBody = CAST(@messageBody as xml);  
with xmlnamespaces (DEFAULT N'http://schemas.microsoft.com/SQL/ServiceBroker/Error')  
select @errorNumber = @xmlBody.value ('(/Error/Code)[1]', 'INT'),  
@errorMessage = @xmlBody.value ('(/Error/Description)[1]', 'NVARCHAR(4000)');  
-- Update the request with the received error  
select @token = [conversation_id]  
from sys.conversation_endpoints  
where [conversation_handle] = @h;  
update [LoadCDRResults] set  
[error_number] = @errorNumber  
, [error_message] = @errorMessage  
where [token] = @token;  
end conversation @h;  
end  
else  
begin  
raiserror(N'Received unexpected message type: %s', 16, 50, @messageTypeName);  
end  
     end  
commit;  
end try  
begin catch  
    declare @error int  
      , @message nvarchar(2048);  
    select @error = ERROR_NUMBER()  
      , @message = ERROR_MESSAGE()  
      , @xactState = XACT_STATE();  
    if (@xactState <> 0)  
     begin  
      rollback;  
     end;  
    raiserror(N'Error: %i, %s', 1, 60, @error, @message) with log;  
end catch  

+0

配置隊列,使其一次只處理一條消息? – Andomar

回答

0

我假設你已經同時運行該程序的多個實例。我期望這些實例中的一個獲得第一行的鎖定,並且所有其他實例都必須等待獲取第一行的鎖定。另一種方法是讀取前n行,並使用readpast鎖定提示來跳過鎖定的行。