Svi*_*vip 3 sql t-sql sql-server deadlock
考虑以下两个表:
create table testDeadlockTable1 (
c1 int not null,
c2 int not null
)
create table testDeadlockTable2 (
c1 int not null,
c2 int not null
)
Run Code Online (Sandbox Code Playgroud)
有了这些数据:
insert testDeadlockTable1 values (1, 1)
insert testDeadlockTable1 values (2, 2)
insert testDeadlockTable1 values (3, 3)
insert testDeadlockTable1 values (4, 4)
insert testDeadlockTable2 values (1, 1)
insert testDeadlockTable2 values (2, 2)
insert testDeadlockTable2 values (3, 3)
insert testDeadlockTable2 values (4, 4)
Run Code Online (Sandbox Code Playgroud)
并考虑以下两个存储过程:
create proc testDeadlockTestA
as
begin tran
update testDeadlockTable1
set c1 = 3
where c2 = 1
waitfor delay '00:00:01' -- sleep 1 second
select c1
from testDeadlockTable2
where c2 = 3
commit tran
go
create proc testDeadlockTestB
as
begin tran
update testDeadlockTable2
set c1 = 5
where c2 = 2
waitfor delay '00:00:01' -- sleep 1 second
select c1
from testDeadlockTable1
where c2 = 4
commit tran
go
Run Code Online (Sandbox Code Playgroud)
在一个查询会话中,调用testDeadlockTestA然后立即在另一个会话调用中testDeadlockTestB.后一届会议将被选为死锁受害者.
在两个会话中,最后@@trancount都是0.
现在启动每个查询会话begin tran,以便@@trancount在调用存储过程时为1.因此,死锁应该发生在每个存储过程开始的事务中(即内部事务).
没有被选为死锁牺牲品的会话A的a @@trancount为1,正如我们所期望的那样(我们没有结束外部事务).但是受害者会话B的得分@@trancount为0.
为什么在发生死锁时内部事务和外部事务都结束了?有没有办法确保只有内部事务在死锁的情况下结束?
看起来好像死锁错误的行为好像XACT_ABORT被设置为on(在这种情况下不是这样),因为不会执行导致死锁的调用之后的任何进一步查询语句.
这个问题的原因是,如果发生死锁,是否可以再次运行查询.如果一个更大的事务中发生,即用于几个查询中被调用,那么会销毁外交易将意味着它会不会是安全地重新运行由死锁牺牲品的查询.但如果它只是停止其周围的环境,那么它将是安全的.
SQL Server没有真正的嵌套事务.有喜欢的功能SAVE TRANSACTION和那样的,或许可以迫使诸如嵌套事务工作的保存点的名称,但不是真的1.
因此ROLLBACK,无论嵌套级别如何,(不尝试使用保存点)的行为总是会影响所有事务.
并且死锁断路器强制执行的回滚永远不会指定保存点名称.
1值得注意的是,每个人都必须"开玩笑".您不能将现有的代码编写为使用BEGIN/ ROLLBACK并将其嵌套在事务中.它必须重写为SAVE TRANSACTION name/ ROLLBACK name现在它依赖于调用代码以始终将其包装在现有事务中