鉴于此设置。
DROP TABLE T1;
CREATE TABLE T1
(RECNUM INTEGER NOT NULL IDENTITY(1,1),
ID INTEGER NOT NULL,
WHO VARCHAR(10) NOT NULL,
DT DATETIME2 NULL DEFAULT(GETDATE())
CONSTRAINT T1_PK_ID PRIMARY KEY CLUSTERED (ID)
);
GO
CREATE TRIGGER [dbo].[T1_TR_AI] ON [dbo].[T1]
AFTER INSERT
AS
BEGIN
SET NOCOUNT ON;
UPDATE A
SET A.ID = B.RECNUM
FROM T1 A
INNER JOIN inserted B ON (A.RECNUM = B.RECNUM)
END;
GO
然后在我的工作站上从两个不同的SSMS实例运行这两个脚本(注意Sql实例也在我的工作站上)
BEGIN TRANSACTION
INSERT INTO T1 (ID,WHO) VALUES (0,'A')
COMMIT TRANSACTION
GO 50000
BEGIN TRANSACTION
INSERT INTO T1 (ID,WHO) VALUES (0,'B')
COMMIT TRANSACTION
GO 50000
我如何得到这样的死锁?
<deadlock>
<victim-list>
<victimProcess id="process4835828" />
</victim-list>
<process-list>
<process id="process4835828" taskpriority="0" logused="144" waitresource="KEY: 13:72057594043695104 (78d82fa561ac)" waittime="3135" ownerId="1466503" transactionname="user_transaction" lasttranstarted="2018-01-08T09:14:34.080" XDES="0x2db10f0" lockMode="X" schedulerid="5" kpid="12496" status="suspended" spid="63" sbid="0" ecid="0" priority="0" trancount="2" lastbatchstarted="2018-01-08T09:14:34.080" lastbatchcompleted="2018-01-08T09:14:34.080" lastattention="1900-01-01T00:00:00.080" clientapp="Microsoft SQL Server Management Studio - Query" hostname="W1643558" hostpid="11600" loginname="WHQ_NT_DOMAIN\KH027556" isolationlevel="read committed (2)" xactid="1466503" currentdb="13" lockTimeout="4294967295" clientoption1="671090784" clientoption2="390200">
<executionStack>
<frame procname="adhoc" line="2" stmtstart="50" stmtend="132" sqlhandle="0x02000000f18dec12c7d493965de43d9ee9f3ec2f8011251800000000000000000000000000000000">
unknown </frame>
<frame procname="adhoc" line="2" stmtstart="38" stmtend="112" sqlhandle="0x020000001fafbb0e5b05c5ef76c1ba0a063e1165cb71b82c00000000000000000000000000000000">
unknown </frame>
</executionStack>
<inputbuf>
BEGIN TRANSACTION
INSERT INTO T1 (ID,WHO) VALUES (0,'A')
COMMIT TRANSACTION
</inputbuf>
</process>
<process id="process484d630" taskpriority="0" logused="272" waitresource="PAGE: 13:1:334 " waittime="3121" ownerId="1466501" transactionname="user_transaction" lasttranstarted="2018-01-08T09:14:34.070" XDES="0x2dbeed0" lockMode="U" schedulerid="8" kpid="19972" status="suspended" spid="62" sbid="0" ecid="0" priority="0" trancount="2" lastbatchstarted="2018-01-08T09:14:34.070" lastbatchcompleted="2018-01-08T09:14:34.070" lastattention="1900-01-01T00:00:00.070" clientapp="Microsoft SQL Server Management Studio - Query" hostname="W1643558" hostpid="11780" loginname="WHQ_NT_DOMAIN\KH027556" isolationlevel="read committed (2)" xactid="1466501" currentdb="13" lockTimeout="4294967295" clientoption1="673319008" clientoption2="390200">
<executionStack>
<frame procname="playground.dbo.T1_TR_AI" line="6" stmtstart="316" stmtend="558" sqlhandle="0x03000d00abe7e85608a7970062a80000000000000000000000000000000000000000000000000000">
UPDATE A
SET A.ID = B.RECNUM
FROM T1 A
INNER JOIN inserted B ON (A.RECNUM = B.RECNUM </frame>
<frame procname="adhoc" line="2" stmtstart="50" stmtend="132" sqlhandle="0x02000000f18dec12c7d493965de43d9ee9f3ec2f8011251800000000000000000000000000000000">
unknown </frame>
<frame procname="adhoc" line="2" stmtstart="38" stmtend="112" sqlhandle="0x0200000018ea0a3996f68c35648ac322cee2d05b887ef67f00000000000000000000000000000000">
unknown </frame>
</executionStack>
<inputbuf>
BEGIN TRANSACTION
INSERT INTO T1 (ID,WHO) VALUES (0,'B')
COMMIT TRANSACTION
</inputbuf>
</process>
</process-list>
<resource-list>
<keylock hobtid="72057594043695104" dbid="13" objectname="playground.dbo.T1" indexname="T1_PK_ID" id="lock1da17580" mode="X" associatedObjectId="72057594043695104">
<owner-list>
<owner id="process484d630" mode="X" />
</owner-list>
<waiter-list>
<waiter id="process4835828" mode="X" requestType="wait" />
</waiter-list>
</keylock>
<pagelock fileid="1" pageid="334" dbid="13" subresource="FULL" objectname="playground.dbo.T1" id="lock20938f00" mode="IX" associatedObjectId="72057594043695104">
<owner-list>
<owner id="process4835828" mode="IX" />
</owner-list>
<waiter-list>
<waiter id="process484d630" mode="U" requestType="convert" />
</waiter-list>
</pagelock>
</resource-list>
</deadlock>
我也尝试使用“而不是触发器”;
CREATE TRIGGER [dbo].[T1_TR_II] ON [dbo].[T1]
INSTEAD OF INSERT
AS
BEGIN
BEGIN TRAN
INSERT T1
SELECT ID, WHO, DT
FROM inserted;
UPDATE T1
SET ID=RECNUM
WHERE RECNUM = @@IDENTITY
COMMIT TRAN
END
仍遇到死锁。插入和触发器不是作为一个事务发生的,或者至少是嵌套事务吗?
答案 0 :(得分:2)
您尝试在另一个线程上插入T1
的同时更新T1
。
两个事务中的insert语句需要对表进行独占锁定并在事务持续期间保持它(i.e. TABLOCKX, HOLDLOCK
),这样一旦有了锁,它们也可以自由地更新表在插入之后,没有死锁与另一个事务试图做同样的事情。