我的应用程序的一部分在以事务隔离级别REPEATABLE READ打开连接后根据业务逻辑更新表。在极少数情况下,如果此操作与应用程序的另一部分重叠,该部分将打开不同的连接并尝试将相同记录重置为其默认值,则会出现以下错误:
Msg 1205, Level 13, State 45, Line 7
Transaction (Process ID 60) was deadlocked on lock resources with another process and has been chosen as the deadlock victim. Rerun the transaction.
我可以使用以下示例来复现问题。
1.
create table Accounts
(
id int identity(1,1),
Name varchar(50),
Amount decimal
)
2.
insert into Accounts (Name,Amount) values ('ABC',5000)
insert into Accounts (Name,Amount) values ('WXY',4000)
insert into Accounts (Name,Amount) values ('XYZ',4500)
3.
以可重复读的隔离级别启动长事务。
Set transaction isolation level REPEATABLE READ
begin tran
declare @var int
select @var=amount
from Accounts
where id=1
waitfor delay '0:0:10'
if @var > 4000
update accounts
set amount = amount -100;
Commit
4.
在执行步骤3的同时,在另一个连接上启动另一个事务。
Begin tran
update accounts
set Amount = 5000
where id = 1
commit tran
在第三步开始的交易最终会完成,但在第四步开始的交易将会失败,并且出现以下错误信息。
Msg 1205, Level 13, State 45, Line 7
Transaction (Process ID 60) was deadlocked on lock resources with another process and has been chosen as the deadlock victim. Rerun the transaction.
我应该如何操作才能在第4步最终运行事务呢?我的想法是将记录重置为默认值,并且在这种情况下执行的任何其他事务都应该被覆盖。如果两个事务不同时进行,那么我就看不到任何问题。
Account
表是一个没有任何非聚集索引的堆表吗? - Bogdan Sahlean