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

SQL Server中捕获用户手动中止存储过程场景以完善审计记录

解决SQL Server存储过程手动中止时的审计状态更新问题

针对用户手动中止存储过程导致审计记录停留在Running状态的问题,可通过以下几种方案逐步完善审计流程:

方案一:TRY...CATCH 结合 XACT_ABORT 捕获用户中止错误

用户通过SSMS手动停止存储过程时,SQL Server会抛出特定错误(如错误号121:The query has been canceled by the user.)。通过在存储过程中启用SET XACT_ABORT ON并结合TRY...CATCH块,可捕获这类中断事件并更新审计状态。

CREATE PROCEDURE YourTargetProcedure
AS
BEGIN
    SET NOCOUNT ON;
    SET XACT_ABORT ON; -- 确保严重中断触发CATCH逻辑

    DECLARE @AuditID INT;
    DECLARE @CurrentSessionID INT = @@SPID;

    -- 1. 插入初始审计记录,同时存储会话ID
    INSERT INTO Audit (StartTime, Status, SessionID)
    VALUES (GETDATE(), 'Running', @CurrentSessionID);
    SET @AuditID = SCOPE_IDENTITY();

    BEGIN TRY
        -- 存储过程核心业务逻辑
        -- ...

        -- 2. 无错误完成,更新状态为Complete
        UPDATE Audit
        SET Status = 'Complete', EndTime = GETDATE()
        WHERE AuditID = @AuditID;
    END TRY
    BEGIN CATCH
        DECLARE @ErrorNum INT = ERROR_NUMBER();
        DECLARE @ErrorMsg NVARCHAR(4000) = ERROR_MESSAGE();

        -- 匹配用户中止相关错误号,可根据实际环境补充
        IF @ErrorNum IN (121, 233, 0)
            UPDATE Audit
            SET Status = 'Canceled', EndTime = GETDATE(), ErrorDetails = @ErrorMsg
            WHERE AuditID = @AuditID;
        ELSE
            UPDATE Audit
            SET Status = 'Error', EndTime = GETDATE(), ErrorDetails = @ErrorMsg
            WHERE AuditID = @AuditID;

        -- 可选:重新抛出错误,保留原有错误抛出逻辑
        THROW;
    END CATCH
END

方案二:服务器级会话终止触发器(补充场景)

如果遇到强制断开连接等TRY...CATCH无法覆盖的场景,可创建服务器级触发器捕获会话终止事件,更新对应审计记录。需注意该方案需要服务器级权限,且需在Audit表中存储会话ID(SessionID)字段。

CREATE TRIGGER AuditSessionDisconnectTrigger
ON ALL SERVER
FOR DISCONNECT
AS
BEGIN
    SET NOCOUNT ON;

    -- 更新当前终止会话中未完成的审计记录
    UPDATE a
    SET a.Status = 'Canceled', a.EndTime = GETDATE()
    FROM Audit a
    WHERE a.SessionID = @@SPID
      AND a.Status = 'Running';
END

方案三:定期清理作业(兜底方案)

创建SQL Server Agent定期作业,扫描并标记超时的Running状态审计记录,避免无效记录长期存在。例如,标记超过1小时未完成的记录为Stale:

-- 定期执行的清理脚本
UPDATE Audit
SET Status = 'Stale', EndTime = GETDATE()
WHERE Status = 'Running'
  AND StartTime < DATEADD(HOUR, -1, GETDATE());

方案优先级建议

  1. 优先使用方案一:存储过程内处理,实时性强且权限要求低,覆盖绝大多数手动中止场景;
  2. 用方案二作为补充:处理强制断开连接等极端场景;
  3. 方案三作为兜底:确保审计数据的准确性和整洁性。

内容的提问来源于stack exchange,提问作者user68288

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.21 20:48:45