You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

SQL Server回滚事务后执行Update语句锁表原因咨询

问题原因分析与解决方案

你的问题核心在于事务没有正确结束,导致UPDATE语句持有的锁一直无法释放,进而阻塞后续的SELECT查询。我们来一步步拆解:

关键问题点

  1. 保存点回滚后事务仍处于活跃状态
    在你的代码里,TRY块中开启了一个事务并创建了保存点T1,当除零异常触发CATCH块时,你执行了ROLLBACK TRANSACTION T1——这只是回滚到保存点,整个事务并没有结束,仍然处于打开状态。

  2. UPDATE在未结束的事务中执行
    随后的UPDATE语句是在这个未关闭的事务中执行的,SQL Server会为这个UPDATE操作添加排他锁(X锁)。由于事务始终没有提交或完全回滚,这个锁会一直被持有,直到会话结束,这就导致后续对该表的SELECT查询被阻塞(默认隔离级别READ COMMITTED下,查询需要等待排他锁释放)。

  3. 缺少对事务状态的判断与收尾
    你没有在CATCH块中检查事务的状态(通过XACT_STATE()函数),也没有在处理完异常后关闭整个事务,这是锁无法释放的根本原因。

修正后的存储过程代码

ALTER PROCEDURE Test_Tran 
AS 
BEGIN
    BEGIN TRY
        BEGIN TRANSACTION
        SAVE TRANSACTION T1;
        SELECT 1 / 0; -- 触发异常
        COMMIT TRANSACTION
    END TRY
    BEGIN CATCH
        -- 检查事务是否处于可回滚状态
        IF XACT_STATE() <> 0
        BEGIN
            -- 直接回滚整个事务,因为TRY块中的操作都需要撤销
            ROLLBACK TRANSACTION;
        END

        -- 在事务外部执行UPDATE,此时会自动提交(自动事务模式)
        UPDATE [DI].[BOMLC_AMPL_DI_Async_Exec_Results] 
        SET [End_Time] = GETDATE(), 
            [Execution_Status] = 'FAILED', 
            [Error_Number] = ERROR_NUMBER(), -- 用系统函数获取真实错误号
            [Error_Message] = 'Exception occurred while processing: ' + ERROR_MESSAGE(), 
            [Last_Updated_On] = GETDATE() 
        WHERE [Token_ID] = 52;

        PRINT('Something went wrong');
    END CATCH
END
GO

EXEC Test_Tran;

关键修正说明

  • 完全回滚事务:在CATCH块中,通过XACT_STATE()判断事务状态,若事务存在则直接回滚整个事务——你的场景中TRY块内的操作全部需要撤销,保存点在这里没有实际意义。
  • 在事务外部执行UPDATE:将UPDATE放在事务关闭之后执行,这样UPDATE会在SQL Server的自动提交模式下运行,执行完成后立即释放锁,不会阻塞后续查询。
  • 使用系统函数获取错误信息:替换硬编码的16为ERROR_NUMBER(),能更准确地捕获实际错误号。

额外验证技巧

你可以通过以下语句查看当前锁状态,验证锁是否正常释放:

SELECT * FROM sys.dm_tran_locks WHERE resource_database_id = DB_ID('你的数据库名');

内容的提问来源于stack exchange,提问作者Prateek Kumar Dalbehera

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.14 09:11:14