在SQL Server中如何捕获存储过程执行异常

落瑶酱_7271

落瑶酱_7271

2026-10-15

298人浏览

原创

try…catch仅捕获运行时错误,不捕获编译期错误;error_*函数值须在catch首行立即保存;事务回滚前需校验xact_state()和@@trancount;错误需用throw或select显式返回应用层。

在sql server中如何捕获存储过程执行异常

TRY…CATCH 只捕获运行时错误,不捕获编译期错误

直接结论:BEGIN TRY 块里写的语句,如果在解析阶段就失败(比如表名写错、语法有误、列不存在),压根不会执行到 TRY,更不会进 CATCH。这类错误在存储过程创建时或首次调用前的批处理解析阶段就被拦截了。

常见“以为能捕获却失败”的例子:

  • SELECT * FROM NonExistentTable —— 编译期报错,CATCH 完全无感
  • DECLARE @x INT = 'abc' —— 类型推导发生在编译期,直接终止批处理
  • RAISERROR('msg', 10, 1) —— 严重性=10 是警告,不中断执行,CATCH 不触发;必须 ≥11 才行

真正能进 CATCH 的典型场景:INSERT 违反主键/唯一约束(错误号 2627)、外键冲突(547)、除零(8134)、CONVERT 失败、动态 SQL 执行时报错(如 EXEC('SELECT * FROM NonExistentTable'))。

ERROR_* 函数值只在 CATCH 第一行有效,必须立刻保存

ERROR_MESSAGE()、ERROR_NUMBER() 等函数返回的值不是静态快照,而是依赖当前错误上下文。一旦你在 CATCH 块里执行了任何可能改变执行状态的语句(哪怕只是 SELECT 1 或 PRINT),这些函数后续调用就可能返回 NULL 或覆盖掉原始错误信息。

正确做法是:在 CATCH 块开头第一行,用变量立即捕获全部关键字段:

DECLARE @ErrNum INT = ERROR_NUMBER(),
        @ErrSev INT = ERROR_SEVERITY(),
        @ErrSt INT = ERROR_STATE(),
        @ErrProc NVARCHAR(128) = ERROR_PROCEDURE(),
        @ErrLine INT = ERROR_LINE(),
        @ErrMsg NVARCHAR(4000) = ERROR_MESSAGE();

之后所有日志记录、判断、重抛都基于这些变量,而不是反复调用 ERROR_* 函数。

Krene
Krene

一款AI图像与设计工具,主要用于AI游戏美术生成和角色设计平台,适合需要提升相关任务效率的用户。

下载

事务回滚前必须检查 XACT_STATE() 和 @@TRANCOUNT

进了 CATCH ≠ 能直接 ROLLBACK TRANSACTION。SQL Server 有三种事务状态:

  • XACT_STATE() = 1:事务可提交(极少见于错误后)
  • XACT_STATE() = 0:无活动事务(比如错误发生在 BEGIN TRAN 之前)
  • XACT_STATE() = -1:事务不可提交(最常见,如约束冲突后),此时只能回滚,不能提交

盲目写 ROLLBACK 会报错:The ROLLBACK TRANSACTION request has no corresponding BEGIN TRANSACTION。安全写法是:

IF XACT_STATE()  0 AND @@TRANCOUNT > 0
    ROLLBACK TRANSACTION;

如果你自己显式开启了事务,建议加本地标志位控制,避免嵌套调用时误滚外层事务:

DECLARE @TranStarted BIT = 0;
IF @@TRANCOUNT = 0
BEGIN
    BEGIN TRANSACTION;
    SET @TranStarted = 1;
END
-- ... 业务逻辑 ...
IF @TranStarted = 1 AND XACT_STATE()  0
    ROLLBACK TRANSACTION;

错误要传回应用层?必须用 THROW 或 SELECT 显式输出

CATCH 块吞掉错误后,默认不会把错误信息返回给调用方(比如 C# 的 SqlCommand)。如果你需要客户端感知异常,有两个选择:

  • 用 THROW(无参数)原样重抛:它保留原始错误号、严重级、消息和行号,推荐用于日志+透传场景
  • 用 RAISERROR 自定义构造错误,但注意严重级必须 ≥11,且无法完全复现原始堆栈
  • 用 SELECT 返回结果集(如 SELECT @ErrMsg AS ErrorMessage),供应用层读取

别只靠 PRINT 或写日志表——应用层收不到,排查时只能翻数据库日志,效率极低。

最易被忽略的一点:TRY…CATCH 必须紧邻书写,不能被 IF、WHILE 或 BEGIN…END 包裹,否则语法报错;它也不能跨批处理,所以动态 SQL 里的错误,得靠内层 EXEC 自己包一层 TRY…CATCH 才能捕获。

相关文章

PHP速学视频免费教程(入门到精通)
PHP速学视频免费教程(入门到精通)

PHP怎么学习?PHP怎么入门?PHP在哪学?PHP怎么学才快?不用担心,这里为大家提供了PHP速学教程(入门到精通),有需要的小伙伴保存下载就能学习啦!

下载

相关标签:

存储过程

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

相关专题

更多
sqlserver和mysql区别
sqlserver和mysql区别

SQL Server和MySQL是两种广泛使用的关系型数据库管理系统。它们具有相似的功能和用途,但在某些方面存在一些显著的区别。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

2023.08.11

5371

4

数据库三范式
数据库三范式

数据库三范式是一种设计规范,用于规范化关系型数据库中的数据结构,它通过消除冗余数据、提高数据库性能和数据一致性,提供了一种有效的数据库设计方法。本专题提供数据库三范式相关的文章、下载和课程。

2023.06.29

2645

3

如何删除数据库
如何删除数据库

删除数据库是指在MySQL中完全移除一个数据库及其所包含的所有数据和结构,作用包括:1、释放存储空间;2、确保数据的安全性;3、提高数据库的整体性能,加速查询和操作的执行速度。尽管删除数据库具有一些好处,但在执行任何删除操作之前,务必谨慎操作,并备份重要的数据。删除数据库将永久性地删除所有相关数据和结构,无法回滚。

2023.08.14

3881

10

vb怎么连接数据库
vb怎么连接数据库

在VB中,连接数据库通常使用ADO(ActiveX 数据对象)或 DAO(Data Access Objects)这两个技术来实现:1、引入ADO库;2、创建ADO连接对象;3、配置连接字符串;4、打开连接;5、执行SQL语句;6、处理查询结果;7、关闭连接即可。

2023.08.31

2891

3

MySQL恢复数据库
MySQL恢复数据库

MySQL恢复数据库的方法有使用物理备份恢复、使用逻辑备份恢复、使用二进制日志恢复和使用数据库复制进行恢复等。本专题为大家提供MySQL数据库相关的文章、下载、课程内容,供大家免费下载体验。

2023.09.05

947

5

vb中怎么连接access数据库
vb中怎么连接access数据库

vb中连接access数据库的步骤包括引用必要的命名空间、创建连接字符串、创建连接对象、打开连接、执行SQL语句和关闭连接。本专题为大家提供连接access数据库相关的文章、下载、课程内容,供大家免费下载体验。

2023.10.09

2567

5

数据库对象名无效怎么解决
数据库对象名无效怎么解决

数据库对象名无效解决办法:1、检查使用的对象名是否正确,确保没有拼写错误;2、检查数据库中是否已存在具有相同名称的对象,如果是,请更改对象名为一个不同的名称,然后重新创建;3、确保在连接数据库时使用了正确的用户名、密码和数据库名称;4、尝试重启数据库服务,然后再次尝试创建或使用对象;5、尝试更新驱动程序,然后再次尝试创建或使用对象。

2023.10.16

2567

4

vb连接access数据库的方法
vb连接access数据库的方法

vb连接access数据库方法:1、使用ADO连接,首先导入System.Data.OleDb模块,然后定义一个连接字符串,接着创建一个OleDbConnection对象并使用Open() 方法打开连接;2、使用DAO连接,首先导入 Microsoft.Jet.OLEDB模块,然后定义一个连接字符串,接着创建一个JetConnection对象并使用Open()方法打开连接即可。

2023.10.16

2853

3

vb连接数据库的方法
vb连接数据库的方法

vb连接数据库的方法有使用ADO对象库、使用OLEDB数据提供程序、使用ODBC数据源等。详细介绍:1、使用ADO对象库方法,ADO是一种用于访问数据库的COM组件,可以通过ADO连接数据库并执行SQL语句。可以使用ADODB.Connection对象来建立与数据库的连接,然后使用ADODB.Recordset对象来执行查询和操作数据;2、使用OLEDB数据提供程序方法等等。

2023.10.19

2361

3

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
布尔教育燕十八mysql高级视频教程
布尔教育燕十八mysql高级视频教程

共24课时 | 8.6万人学习

魔乐科技oracle视频教程
魔乐科技oracle视频教程

共27课时 | 6.7万人学习

肖文吉Oracle视频教程
肖文吉Oracle视频教程

共33课时 | 9万人学习