DeadLock

  1. What causes the deadlock?

I take “Generate SubAccountId” as example.

<1> At last I find “ A TRIGGER tg_s_SAid_Add ON s_SAid FOR INSERT delay to commit transaction” leads to deadlock

<2>Detailed script about tg_s_SAid_Add as following

--use SeedData

--exec sp_helptext tg_s_SAid_Add

CREATE TRIGGER tg_s_SAid_Add ON s_SAid 

FOR INSERT     

AS     

 DELETE FROM dbo.s_SAid

  1. How to track this trigger

<1> Open two SQL Server Query to execute the following script at the same time.

--SELECT GETDATE()

--WAITFOR TIME '20:21:20'

USE SeedData

DECLARE @count INT

SET @count=1

WHILE(@count<1000)

BEGIN

    SET @count=@count+1

    BEGIN TRY

------------------------------------------Main Process--------------------------------------------------

       DECLARE  @p_Type        CHAR(2)

       DECLARE  @p_CountryId   CHAR(3)

       DECLARE  @r_SecId       CHAR(10)

       SET  @p_Type='SA'     

       SET  @p_CountryId='USA'

        -- Variable declaration

          -- Always set error handling variables first

          DECLARE @l_Err      INTEGER,

                 @l_Msg      NVARCHAR(100),

                 @l_Id       NVARCHAR(15),

                 @l_ProcName VARCHAR(30),

                 @l_ProcDB   VARCHAR(30)

          DECLARE @l_TableName   CHAR(6),

                 @l_Cmd         NVARCHAR(100),

                 @l_OldId       INTEGER,

                 @l_NewId       VARCHAR(5)

          SET NOCOUNT ON

          -- Initialize error handle-related constants

          SET @l_Id       = ISNULL(@p_Type + @p_CountryId,'')

          SET @l_ProcName = OBJECT_NAME (@@PROCID)

          SET @l_ProcDB   = DB_NAME()

          SET @p_Type      = RTRIM(LTRIM(@p_Type))

          SET @p_CountryId = RTRIM(LTRIM(@p_CountryId))

          SET @r_SecId = NULL

          IF @p_Type NOT IN ('F0', 'FO', 'FC', 'FE', 'FM', 'FV', 'FS', 'FX', 'E0', 'VP', 'VA', 'B0', 'C0',

                           'BP', 'BM', 'XI', 'SA', 'SC', 'SP', 'CF', 'FH', 'ST','FA')

          BEGIN

             SET @l_Err = 50001

             SET @l_Msg = 'Invalid input: p_Type.'

             GOTO OnError

          END

          IF LEN(@p_CountryId) <> 3

          BEGIN

             SET @l_Err = 50001

             SET @l_Msg = 'Invalid input: p_CountryId.'

             GOTO OnError

          END

          IF @p_CountryId = '---'

          BEGIN

             SET @p_CountryId = '000'

          END

          SELECT @l_TableName = 's_' + @p_Type + 'id'

          BEGIN TRANSACTION

             SET @l_Cmd = N'INSERT INTO '+@l_TableName+' DEFAULT VALUES'

             EXECUTE sp_executesql @l_Cmd

             SELECT @l_OldId = @@IDENTITY,

                   @l_Err = @@ERROR

             IF @l_Err <> 0

             BEGIN

               ROLLBACK TRANSACTION

               SET @l_Msg = 'Insert on ' + @l_TableName + ' failed.'

               GOTO OnError

             END

             IF @l_OldId > 0 AND @l_OldId <= POWER(36,4)-1

             BEGIN

               SET @l_NewId = ResourceData.dbo.fn_chgDecIntToNBaseInt(36, @l_OldId)

               SET @l_Err = @@ERROR

               IF @l_Err <> 0

               BEGIN

                  ROLLBACK TRANSACTION

                  SET @l_Msg = 'Call on fn_chgDecIntToNBaseInt failed.'

                  GOTO OnError

               END

               IF @l_NewId = NULL

               BEGIN

                  ROLLBACK TRANSACTION

                  SET @l_Err = 50002

                  SET @l_Msg = 'Invalid Id output from fn_chgDecIntToNBaseInt.'

                  GOTO OnError

               END

               SELECT @l_NewId = RIGHT('00000'+@l_NewId,5)

               SELECT @r_SecId = @p_Type + @p_CountryId + @l_NewId

             END

             ELSE

             BEGIN

               ROLLBACK TRANSACTION

               SET @l_Err = 50002

               SET @l_Msg = 'Invalid Id output from insert on ' + @l_TableName

               GOTO OnError

             END

          COMMIT TRANSACTION

          --RETURN @@ERROR

          -- Error handling section

          OnError:

             -- Store error and raise error

             --EXECUTE sp_LogError @l_Err, @l_Msg, @l_Id, @l_ProcName, @l_ProcDB

             --RAISERROR(@l_Msg, 18,1)

             --RETURN @l_Err

---------------------------------------------------Main Process------------------------------------------------------

    END TRY

    BEGIN CATCH

        ROLLBACK TRANSACTION

       DECLARE @ErrorMessage VARCHAR(8000);

       SELECT  @ErrorMessage = 'ErrorMessage: '+ISNULL(CAST(ERROR_MESSAGE() AS VARCHAR(500)),'-')+CHAR(10)+

                                'ERROR_SEVERITY: '+ISNULL(CAST(ERROR_SEVERITY()AS VARCHAR(500)),'-')+CHAR(10)+

                                'ERROR_NUMBER: '+ISNULL(CAST(ERROR_NUMBER()AS VARCHAR(500)),'-')+CHAR(10)+

                                'ERROR_STATE: '+ISNULL(CAST(ERROR_STATE()AS VARCHAR(500)),'-')+CHAR(10)+

                                'ERROR_PROCEDURE: '+ISNULL(CAST(ERROR_PROCEDURE()AS VARCHAR(500)),'-')+CHAR(10)+

                                'ERROR_LINE: '+ISNULL(CAST(ERROR_LINE()AS VARCHAR(500)),'-')

       --if deadlock happened ,print the detailed error message

       IF ERROR_NUMBER()=1205

       BEGIN

         PRINT @ErrorMessage

         BREAK;

       END                            

    END CATCH

END

<2> The print error message as following

ErrorMessage: Transaction (Process ID 51) was deadlocked on lock resources with another process and has been chosen as the deadlock victim. Rerun the transaction.

ERROR_SEVERITY: 13

ERROR_NUMBER: 1205

ERROR_STATE: 45

ERROR_PROCEDURE: tg_s_SAid_Add

ERROR_LINE: 4

<3> We can know code line 4 of trigger “tg_s_SAid_Add”  as the red font leads to the deadlock cregarding the error message 

CREATE TRIGGER tg_s_SAid_Add ON s_SAid 

FOR INSERT     

AS     

 DELETE FROM dbo.s_SAid

<4>we can use a simple example  instead of trigger “tg_s_SAid_Add”  as following to do a text

  1. Create a text table

CREATE TABLE IdText(

               [Id] [int] IDENTITY(1,1) NOT NULL)

  1. b. Open two SQL Server Query to execute the following script at the same time then the same deadlock happened again.

Begin Tran

INSERT INTO IdTable DEFAULT VALUES

   WaitFor Delay '00:01:00';

   DELETE FROM IdTable

Rollback Tran;

  1. A solution to avoid deadlock for above simple example is to seperated the big transaction as following  and

     open two SQL Server Query to execute the following script at the same time then the deadlock will never happened

         INSERT INTO IdTable DEFAULT VALUES

        DELETE FROM IdTable

  1. The solution for u_getCode

<1>drop  TRIGGER of “tg_s_SAid_Add” first.

<2>Execute delete sql script after transaction commit as Yellow highlight

<3>After drop the TRIGGER then open two SQL Server Query to execute the following script

--SELECT GETDATE()

--WAITFOR TIME '20:21:20'

USE SeedData

DECLARE @count INT

SET @count=1

WHILE(@count<1000)

BEGIN

    SET @count=@count+1

    BEGIN TRY

------------------------------------------Main Process--------------------------------------------------

       DECLARE  @p_Type        CHAR(2)

       DECLARE  @p_CountryId   CHAR(3)

       DECLARE  @r_SecId       CHAR(10)

       SET  @p_Type='SA'     

       SET  @p_CountryId='USA'

        -- Variable declaration

          -- Always set error handling variables first

          DECLARE @l_Err      INTEGER,

                 @l_Msg      NVARCHAR(100),

                 @l_Id       NVARCHAR(15),

                 @l_ProcName VARCHAR(30),

                 @l_ProcDB   VARCHAR(30)

          DECLARE @l_TableName   CHAR(6),

                 @l_Cmd         NVARCHAR(100),

                 @l_OldId       INTEGER,

                 @l_NewId       VARCHAR(5)

          SET NOCOUNT ON

          -- Initialize error handle-related constants

          SET @l_Id       = ISNULL(@p_Type + @p_CountryId,'')

          SET @l_ProcName = OBJECT_NAME (@@PROCID)

          SET @l_ProcDB   = DB_NAME()

          SET @p_Type      = RTRIM(LTRIM(@p_Type))

          SET @p_CountryId = RTRIM(LTRIM(@p_CountryId))

          SET @r_SecId = NULL

          IF @p_Type NOT IN ('F0', 'FO', 'FC', 'FE', 'FM', 'FV', 'FS', 'FX', 'E0', 'VP', 'VA', 'B0', 'C0',

                           'BP', 'BM', 'XI', 'SA', 'SC', 'SP', 'CF', 'FH', 'ST','FA')

          BEGIN

             SET @l_Err = 50001

             SET @l_Msg = 'Invalid input: p_Type.'

             GOTO OnError

          END

          IF LEN(@p_CountryId) <> 3

          BEGIN

             SET @l_Err = 50001

             SET @l_Msg = 'Invalid input: p_CountryId.'

             GOTO OnError

          END

          IF @p_CountryId = '---'

          BEGIN

             SET @p_CountryId = '000'

          END

          SELECT @l_TableName = 's_' + @p_Type + 'id'

          BEGIN TRANSACTION

             SET @l_Cmd = N'INSERT INTO '+@l_TableName+' DEFAULT VALUES'

             EXECUTE sp_executesql @l_Cmd

             SELECT @l_OldId = @@IDENTITY,

                   @l_Err = @@ERROR

             IF @l_Err <> 0

             BEGIN

               ROLLBACK TRANSACTION

               SET @l_Msg = 'Insert on ' + @l_TableName + ' failed.'

               GOTO OnError

             END

             IF @l_OldId > 0 AND @l_OldId <= POWER(36,4)-1

             BEGIN

               SET @l_NewId = ResourceData.dbo.fn_chgDecIntToNBaseInt(36, @l_OldId)

               SET @l_Err = @@ERROR

               IF @l_Err <> 0

               BEGIN

                  ROLLBACK TRANSACTION

                  SET @l_Msg = 'Call on fn_chgDecIntToNBaseInt failed.'

                  GOTO OnError

               END

               IF @l_NewId = NULL

               BEGIN

                  ROLLBACK TRANSACTION

                  SET @l_Err = 50002

                  SET @l_Msg = 'Invalid Id output from fn_chgDecIntToNBaseInt.'

                  GOTO OnError

               END

               SELECT @l_NewId = RIGHT('00000'+@l_NewId,5)

               SELECT @r_SecId = @p_Type + @p_CountryId + @l_NewId

             END

             ELSE

             BEGIN

               ROLLBACK TRANSACTION

               SET @l_Err = 50002

               SET @l_Msg = 'Invalid Id output from insert on ' + @l_TableName

               GOTO OnError

             END

          COMMIT TRANSACTION

           --here ,execute delete sql script

           SET @l_Cmd = N'DELETE FROM  '+@l_TableName

           EXECUTE sp_executesql @l_Cmd

          --RETURN @@ERROR

          -- Error handling section

          OnError:

             -- Store error and raise error

             --EXECUTE sp_LogError @l_Err, @l_Msg, @l_Id, @l_ProcName, @l_ProcDB

             --RAISERROR(@l_Msg, 18,1)

             --RETURN @l_Err

---------------------------------------------------Main Process------------------------------------------------------

    END TRY

    BEGIN CATCH

        ROLLBACK TRANSACTION

       DECLARE @ErrorMessage VARCHAR(8000);

       SELECT  @ErrorMessage = 'ErrorMessage: '+ISNULL(CAST(ERROR_MESSAGE() AS VARCHAR(500)),'-')+CHAR(10)+

                                'ERROR_SEVERITY: '+ISNULL(CAST(ERROR_SEVERITY()AS VARCHAR(500)),'-')+CHAR(10)+

                                'ERROR_NUMBER: '+ISNULL(CAST(ERROR_NUMBER()AS VARCHAR(500)),'-')+CHAR(10)+

                                'ERROR_STATE: '+ISNULL(CAST(ERROR_STATE()AS VARCHAR(500)),'-')+CHAR(10)+

                                'ERROR_PROCEDURE: '+ISNULL(CAST(ERROR_PROCEDURE()AS VARCHAR(500)),'-')+CHAR(10)+

                                'ERROR_LINE: '+ISNULL(CAST(ERROR_LINE()AS VARCHAR(500)),'-')

       --if deadlock happened ,print the detailed error message

       IF ERROR_NUMBER()=1205

       BEGIN

         PRINT @ErrorMessage

         BREAK;

       END                            

    END CATCH

END

<4>Text more times find everything is ok

转载于:https://www.cnblogs.com/flysun0311/archive/2010/11/25/1887813.html

猜你喜欢

转载自blog.csdn.net/weixin_33853827/article/details/93444255