处理死锁

时间:2014-01-15 13:26:14

标签: sql-server transactions deadlock

我有一个程序(usp_LoadCDRActivated)调用另一个程序(usp_crs_LoadCDRsByBatch)。 proc usp_crs_LoadCDRsByBatch调用了另外六个过程,这些过程将数据从单个临时表加载到其他汇总表。我通过队列运行父proc(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      

结束

1 个答案:

答案 0 :(得分:0)

我假设您有多个此过程并发运行的实例。我希望其中一个实例获得第一行的锁定,所有其他实例必须等待获取第一行的锁定。另一种方法是读取前n行并使用readpast锁定提示跳过锁定的行。