自定义异常需显式RAISE触发,是DECLARE段声明的EXCEPTION类型变量,不带错误号和消息;捕获时WHEN子句必须严格匹配声明名;RAISE仅激活命名异常,RAISE_APPLICATION_ERROR则带指定错误码和消息并终止块。

自定义异常不能靠“自动触发”,必须显式 RAISE 才生效;它本身不带错误号、不带消息,只是一个命名的逻辑开关。
声明自定义异常变量必须在 DECLARE 段
自定义异常是类型为 EXCEPTION 的变量,只能在 PL/SQL 块的声明区(DECLARE)中定义,不能在 BEGIN 里声明,也不能赋值或初始化。
- ✅ 正确写法:
v_invalid_input EXCEPTION; - ❌ 错误写法:
v_invalid_input := -20001;(报PLS-00382) - ❌ 错误写法:
RAISE v_invalid_input;出现在DECLARE段(报PLS-00103) - ⚠️ 注意:变量名区分大小写,
WHEN子句中必须用完全一致的拼写
触发自定义异常只能用 RAISE 或 RAISE_APPLICATION_ERROR
自定义异常不会因 SQL 报错而自动激活,必须由业务逻辑判断后手动抛出。两种方式语义和行为不同:
-
RAISE v_exception;:仅激活该命名异常,SQLCODE默认为1,SQLERRM固定为"User-Defined Exception" -
RAISE_APPLICATION_ERROR(-20001, 'Input too large');:立即终止当前块,向上层传播,带指定错误码和消息;此时无需提前声明EXCEPTION变量 - ⚠️ 如果用了
PRAGMA EXCEPTION_INIT(v_exc, -20001),再RAISE v_exc,SQLCODE才会是-20001;但若直接RAISE_APPLICATION_ERROR(-20001, ...),就绕过了这个 pragma
捕获时 WHEN 子句必须与声明名严格匹配
PL/SQL 不支持通配或模糊匹配,异常名大小写、下划线、拼写全部需一致,否则进入 WHEN OTHERS 分支,容易掩盖问题。
- 声明了
no_dept_found EXCEPTION;,就必须写WHEN no_dept_found THEN - 写成
WHEN NO_DEPT_FOUND THEN(全大写)或WHEN nodptfound THEN(少下划线)均无法捕获 - 若想复用标准错误码,推荐用
RAISE_APPLICATION_ERROR+WHEN OTHERS,而不是强行绑定PRAGMA EXCEPTION_INIT
别混淆自定义异常和非预定义异常
非预定义异常(如违反外键约束的 ORA-02292)本质是 Oracle 系统错误,只是没内置名字;而自定义异常完全脱离 Oracle 错误体系,纯属程序逻辑信号。
- 非预定义异常需要
PRAGMA EXCEPTION_INIT关联错误号,才能用WHEN捕获 - 自定义异常不需要、也不能关联 Oracle 错误号——除非你主动用
RAISE_APPLICATION_ERROR模拟一个 - 常见误操作:给自定义异常写
PRAGMA EXCEPTION_INIT(v_err, -20001)后,又在BEGIN里RAISE_APPLICATION_ERROR(-20001, ...),这会导致重复定义,且WHEN v_err仍能捕获,但语义已混乱
真正难的不是写几行 EXCEPTION 声明,而是想清楚:这个“异常”到底代表系统错误、约束冲突,还是纯粹的业务规则不满足?前者该用 PRAGMA 或 RAISE_APPLICATION_ERROR,后者才适合裸 RAISE + 自定义名。


















