mysql用signal、sql server用throw/raiserror、oracle用raise_application_error;均需在before触发器中主动抛出,不可捕获,且signal须配message_text,raiserror级别≥11,raise_application_error错误号限-20000~-20999、消息≤2048字节。

能,但方式因数据库而异:MySQL 用 SIGNAL,SQL Server 用 THROW 或 RAISERROR,Oracle 用 RAISE_APPLICATION_ERROR;统一原则是——不能捕获,只能主动抛出,且必须在 BEFORE 阶段做判断。
MySQL 触发器里怎么用 SIGNAL 抛错
只允许在 BEFORE 触发器中使用,AFTER 里虽语法通过,但若再操作同表会先报 Can't update table in stored function/trigger,SIGNAL 根本没机会执行。
-
SIGNAL SQLSTATE '45000'是标准写法,'45000' 表示通用用户错误,避免和系统错误混淆 - 必须搭配
SET MESSAGE_TEXT = 'xxx',否则客户端收到的是空错误或默认模糊提示 - 查重逻辑(如
IF EXISTS (SELECT 1 FROM users WHERE email = NEW.email))要确保字段有索引,否则全表扫描拖慢写入 - 别写
SELECT email INTO @tmp再判空——查不到会直接触发ERROR 1329 (02000),且无法拦截
SQL Server 触发器里 TRY…CATCH 为什么常失效
不是语法不支持,而是结构被破坏:触发器本身是一个批处理单元,BEGIN TRY 和 BEGIN CATCH 必须连续出现,中间不能有 GO、不能跨批、也不能藏在动态 SQL 里。
-
ERROR_NUMBER()、ERROR_MESSAGE()等函数只在CATCH块内有效,离开就返回NULL - 捕获后不
THROW或RAISERROR,上层应用(如 C# 的SqlCommand)根本收不到异常,事务也不会自动回滚 -
RAISERROR的severity必须 ≥ 11 才能被CATCH捕获;业务场景推荐用 16,别用 20+(会断开连接) - 触发器中抛错后必须显式
ROLLBACK TRANSACTION,否则数据可能已写入但错误被“吞掉”
Oracle 触发器里 RAISE_APPLICATION_ERROR 的硬限制
这是唯一能穿透到 JDBC/OCI 层的自定义错误方式,但编号和长度卡得很死。
- 错误号必须是
-20000到-20999之间的整数,传-1000或-30000会编译失败,报PLS-00302 - 消息字符串不能超过 2048 字节,超长部分静默截断,不报错也不警告
- 第二参数不能为空字符串,否则 Oracle 报
ORA-20000(只剩一个冒号) - 不能在 SQL 表达式中调用(比如
SELECT ... FROM t WHERE f() = 1),只能放在 PL/SQL 块里
真正容易被忽略的是:所有数据库的触发器都不支持异常捕获机制(如 DECLARE HANDLER 或 TRY 嵌套),你只能预判条件、提前中断,没法“try 一下再 fallback”。校验越重,越该移到应用层——触发器只适合轻量、确定、无副作用的拦截。











