在表A上插入后,我有一个表A
(id int, domain nvarchar, status nvarchar
)和触发器A_trigger
。触发器调用存储过程,并根据过程的结果更新新插入的行上的状态。
当我在两个会话中运行它时,最终会遇到死锁问题:
隔离级别:读取已提交
INSERT
语句:
INSERT INTO dbo.TEST_TRIGGER (DOMAIN)
VALUES ('toto')
触发:
CREATE TRIGGER dbo.dim_trigger
ON db.dbo.TEST_TRIGGER
AFTER INSERT
AS
DECLARE @status nvarchar(200),
@domain nvarchar(200),
@trackingId int
BEGIN
SET NOCOUNT ON;
-- This code assumes we insert one and only one row at a time.
SELECT @trackingId = id, @domain = domain FROM INSERTED;
DECLARE @toCallProcName NVARCHAR(200);
SET @toCallProcName = 'db.dbo.'+@domain+'_proc';
EXEC @toCallProcName @status out;
UPDATE db.dbo.TEST_TRIGGER
SET status = @status
WHERE id = @trackingId;
END
我试图:
WITH (UPDLOCK)
发出更新语句,但这不起作用EDIT1 :
表架构:
CREATE TABLE [dbo].[TEST_TRIGGER]
(
[DOMAIN] [NVARCHAR](200) NOT NULL,
[ID] [BIGINT] IDENTITY(1,1) NOT NULL,
[STATUS] [NVARCHAR](100) NULL
)
存储过程:
CREATE PROCEDURE [dbo].[toto_proc]
@res NVARCHAR(200) OUTPUT
AS
BEGIN
SET NOCOUNT ON;
WAITFOR DELAY '00:00:5'
PRINT 'This is me: '+CONVERT(VARCHAR(8), GETDATE(), 108) ;
SET @res = 'OK'
END
有帮助吗?
谢谢
答案 0 :(得分:1)
您需要做的是在表上创建索引
示例:
CREATE INDEX IX_Test_Trigger ON dbo.TEST_TRIGGER(Id)
请阅读以下内容以获取有关Index及其对锁定机制的影响的更多信息: https://www.mssqltips.com/sqlservertip/2517/using-a-clustered-index-to-solve-a-sql-server-deadlock-issue/
答案 1 :(得分:1)
您遇到的问题的原因是,触发器将锁保持在基表上。由于多个会话和相同的资源,这势必会发生。在表上没有索引将导致每次针对每个不同的会话进行表扫描并导致死锁。应用索引是正确的举动,因为这样您的update语句将达到粒度级别。所以这应该工作。我建议在更新语句中额外提示RowLock。