提交后Sql事务不释放锁

msl*_*viu 5 sql sql-server ssms transactions

我在 SSMS 查询窗口中运行了一个类似于下面的脚本。脚本成功运行后,受影响的表上保留了一些锁。当我尝试关闭窗口时,会显示一个消息框,询问我是要提交还是取消事务。

在我选择其中一个选项后,锁定被释放。什么会导致这种行为?

begin tran
delete from tableA
delete from tableB
insert into tableB
insert into tableA
commit tran 
Run Code Online (Sandbox Code Playgroud)

我已连接到远程 Sql Server 2014 并运行本地 SSMS 2014

谢谢!

Shr*_*e29 5

以下示例说明了未完成的打开事务导致锁如何不被释放:打开 SQL Server 查询分析器并运行以下批处理,但在事务完成之前取消该事务:

Begin Tran
Update authors set state = 'CA'
waitfor delay "00:02:00" --Cancel the command
Commit Tran
Run Code Online (Sandbox Code Playgroud)

通过执行以下命令查看持有的锁:

sp_lock
Run Code Online (Sandbox Code Playgroud)

您会看到为authors 表持有锁。

从相同的服务器进程 ID (SPID),执行下一批:

Begin Tran
Update titleauthor set au_ord = 0
Commit Tran - Completed transaction.
Run Code Online (Sandbox Code Playgroud)

通过执行以下命令查看持有的锁:

sp_lock
Run Code Online (Sandbox Code Playgroud)

您会看到,虽然最后一个事务已完成,但authors 和titleauthors 表上都持有锁。原因是第一个事务没有完成,当第二个事务从同一个连接执行时,它被视为嵌套事务。

您可以通过发出以下语句检查 @@trancount 全局变量来查看事务计数:

select @@trancount
Run Code Online (Sandbox Code Playgroud)

此查询返回 1,表示有一笔交易未完成。

从此连接执行的任何其他事务都被视为嵌套的。锁会继续累积,直到执行 ROLLBACK 才会释放,这会回滚到最外面的事务或保存点。继续该示例,您可以看到回滚如何通过从同一连接执行以下事务来导致已完成的事务被否定:

Begin Tran
Update titles set royalty = 0
Rollback
Run Code Online (Sandbox Code Playgroud)

回滚会将批处理回滚到最外面的事务,即使 titleauthors 上存在已完成的事务 (2)。已完成事务的回滚发生是因为已完成的事务被视为嵌套事务。

为避免此类问题,请在每次交易后使用以下语句检查交易是否完成:

If @@trancount > 0 rollback
Run Code Online (Sandbox Code Playgroud)

参考:不完整的事务可能持有大量锁导致阻塞