使用 try/catch 进行动态 SQL 备份命令时如何记录错误详细信息

cro*_*sek 10 sql-server backup error-handling

在使用 try catch 和动态 sql 的存储过程中发出备份命令时,与直接运行备份命令相比,错误消息非常普遍。

在 SP 中尝试/捕获:

    begin try
        execute sp_executesql @sql;  -- a backup command
    end try
    begin catch  
        print ERROR_MESSAGE();  -- save to log, etc.
    end catch
Run Code Online (Sandbox Code Playgroud)

结果是

50000:usp_Backup:117: BACKUP DATABASE 异常终止。

whearea 发出原始命令:

    backup DATABASE someDb to disk...
Run Code Online (Sandbox Code Playgroud)

结果更好的细节:

查找错误 - SQL Server 数据库错误:文件“H:\FolderName\Filename.bak:”112(磁盘空间不足。)发生不可恢复的 I/O 错误。

有没有办法将这些细节捕获到存储过程中的变量中(记录,传回调用者,重试逻辑)?似乎细节正在通过消息通道传递,但我希望它们在 SP 中可用。

Aar*_*and 13

BACKUP DATABASE产生一个错误时,它实际上产生了两个。不幸的TRY/CATCH是无法捕获第一个错误;它只捕获第二个错误。

我怀疑捕获失败备份背后真正原因的最佳选择是通过SQLCMD-o将输出发送到文件)、SSIS、C#、PowerShell 等自动备份。所有这些都将使您更好地控制捕获所有的错误。

评论中的 SO 答案建议使用DBCC OUTPUTBUFFER- 虽然有可能,但这似乎根本不是儿戏。随意从 Erland Sommarskog 的网站上享受这个过程的乐趣,但这似乎仍然不能很好地与TRY/CATCH.

我似乎能够捕获错误消息的唯一方法spGET_LastErrorMessage是是否确实抛出了实际错误。如果你把它包装在一个TRY/CATCH错误被吞下并且存储过程什么都不做:

BEGIN TRY
  EXEC sp_executesql N'backup that fails...';
END TRY
BEGIN CATCH
  EXEC dbo.spGet_LastErrorMessage;
END CATCH
Run Code Online (Sandbox Code Playgroud)

在 SQL Server < 2012 中,您不能自己重新引发错误,但在 SQL Server 2012 和更新版本中可以。所以这两个变体有效:

CREATE PROCEDURE dbo.dothebackup
AS
BEGIN
  SET NOCOUNT ON;
  EXEC sp_executesql N'backup that fails...';
END
GO

EXEC dbo.dothebackup;
EXEC dbo.spGET_LastErrorMessage;
Run Code Online (Sandbox Code Playgroud)

或者在 2012 年及以上,这有效,但在很大程度上违背了 的目的TRY/CATCH,因为仍然抛出原始错误:

CREATE PROCEDURE dbo.dothebackup2
AS
BEGIN
  SET NOCOUNT ON;
  BEGIN TRY
    EXEC sp_executesql N'backup that fails...';
  END TRY
  BEGIN CATCH
    THROW;
  END CATCH
END
GO

EXEC dbo.dothebackup2;
EXEC dbo.spGET_LastErrorMessage;
Run Code Online (Sandbox Code Playgroud)

当然,在这两种情况下,错误仍然会被抛出给客户端。因此,如果您要TRY/CATCH避免这种情况,除非有一些我没有想到的漏洞,否则恐怕您将不得不做出选择……要么向用户提供错误并能够捕获有关的详细信息它,或者同时抑制错误和实际原因。