RAISERROR的severity必须≥11才能被TRY...CATCH捕获,0–10为信息性消息不中断执行;推荐业务异常用16级,避免20+致命错误;需注意N前缀、参数匹配、NULL处理、错误号注册及触发器中显式ROLLBACK。

必须用 RAISERROR 且 severity ≥ 11,否则 CATCH 块捕获不到,业务逻辑会继续执行。
RAISERROR 的 severity 参数为什么不能小于 11
SQL Server 中 RAISERROR 的 severity 决定是否触发 CATCH 分支。0–10 级别属于“信息性消息”,不会中断执行流,也不会跳转到 CATCH;只有 11–19 级别才会被 TRY...CATCH 捕获。
- 常见错误:写成
RAISERROR('xxx', 10, 1)→CATCH完全不执行,后续语句照常运行 - 推荐值:业务异常统一用
16(标准用户错误级别,安全、可捕获、不终止连接) - 绝对避免:用
20+—— 触发致命错误,客户端连接直接断开,C# 里收到的是“传输级错误”,原始消息丢失
抛出带动态参数的错误消息(比如 ID、名称)
用占位符 %s、%d 配合参数列表,比字符串拼接更安全(防 SQL 注入、空值崩溃)。
- 正确写法:
RAISERROR(N'员工 %s 不存在', 16, 1, @empName) - 注意:
N''前缀必须加,否则中文乱码或截断 - 参数个数要严格匹配占位符数量,多一个少一个都会报错
Msg 102, Level 15, State 1 - 变量为
NULL时,对应占位符显示为(null),不是空字符串
自定义错误号(msg_id)要不要注册到 sys.messages
不用提前注册也能用,但注册后更利于统一管理和本地化。
- 临时用法:直接传字符串,如
RAISERROR('库存不足', 16, 1)→ 错误号固定为50000 - 正式项目建议注册:用
sp_addmessage添加错误号 ≥ 50001(系统保留 1–49999),例如:EXEC sp_addmessage 50001, 16, N'订单状态非法' - 注册后可用
RAISERROR(50001, 16, 1),消息内容从sys.messages查,支持多语言切换 - 注意:
sp_addmessage需要sysadmin权限,开发环境可做,生产库需 DBA 协作
在触发器里 RAISERROR 后要不要显式 ROLLBACK
要。触发器中 RAISERROR 不会自动回滚当前事务,必须手动 ROLLBACK TRANSACTION。
- 典型错误模式:
RAISERROR('禁止删除主记录', 16, 1)→ 没ROLLBACK→ 删除仍生效 - 正确顺序:
RAISERROR(...); ROLLBACK TRANSACTION; RETURN; - 如果触发器外层已有事务(比如应用层 BEGIN TRAN),
ROLLBACK会回滚整个事务,这是预期行为 - 注意:
SET XACT_ABORT ON可辅助保障事务一致性,但不能替代显式ROLLBACK
真正容易被忽略的是:RAISERROR 在函数里完全不可用 —— SQL Server 函数禁止副作用操作,包括抛异常。业务校验逻辑必须挪到存储过程或触发器里做。

















