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> 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
CREATE TABLE IdText(
[Id] [int] IDENTITY(1,1) NOT NULL)
Begin Tran
INSERT INTO IdTable DEFAULT VALUES
WaitFor Delay '00:01:00';
DELETE FROM IdTable
Rollback Tran;
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>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