CHECK约束不抛出可捕获的PL/SQL异常,仅触发ORA-02290中止语句;需用触发器或存储过程实现复杂校验与自定义处理。
oracle
的
约束本身不抛出可捕获的 pl/sql 异常,它只在违反时直接报
并中止语句执行;想在插入/更新前做复杂校验并自定义处理逻辑,不能只靠
,得用触发器或存储过程封装。
ORA-02290 是什么,为什么它不能被常规 EXCEPTION 捕获
是约束级错误,在 SQL 语句执行阶段由 Oracle 内核强制拦截,不经过 PL/SQL 引擎的异常处理路径。即使你在
块里执行
,只要触发了 CHECK 违反,整个语句就已失败,
部分不会运行——除非你显式用
+
捕获再判断错误号。
它不是 PL/SQL 预定义异常(如
),没有对应异常名,必须靠
判断
若在匿名块中执行 DML 后没加异常处理,会直接报错退出,调用方收不到可控反馈
即便加了
,也需手动检查
才能区分是 CHECK 违反还是其他问题
想让校验可干预,该用触发器而不是 CHECK
当需要在插入前做正则校验、查关联表、调用函数或记录日志时,
触发器比
更灵活。它运行在 PL/SQL 上下文中,可自由使用
、
、
等。
触发器里可以用
抛出自定义错误,调用方能明确识别
支持跨列逻辑,比如
避免老版本 Oracle 对
在 CHECK 中的限制(12.1 及之前不支持)
注意:触发器性能开销略高,高频写入表要测压;且需确保触发器逻辑幂等,避免递归触发
如果坚持用 CHECK,怎么让错误更友好
纯
约束无法改变报错信息内容,但可以通过命名和注释降低维护成本:
oracle知识库
oracle知识库下载
下载
约束名带业务含义,例如
而非
用
补充说明,如
建表时加
先挂载约束,后续用
分批校验存量数据,避免建表失败
对已有数据的表加新 CHECK,务必先确认数据合规,否则会报
(无法验证约束)
真正需要“校验+处理”的场景,绕不开存储过程封装
前端或应用层调用一个统一入口,把校验、插入、错误分类全包在里面,比分散在各处的 CHECK 或触发器更可控:
过程内先用
再
,并在
块中捕获
做降级处理(如写审计表、返回特定码)
所有业务规则集中一处,改格式只需动过程,不用改 N 张表的约束
注意:过程里不要用
记日志,否则约束失败时日志仍会提交,造成数据不一致
CHECK 约束适合静态、轻量、确定性的断言;一旦涉及正则、函数、跨表、空值安全或需要差异化提示,就得交由 PL/SQL 主动控制——它的校验点不在 DDL 层,而在你写的每一行
和
里。
checkora-02290checkORA-02290: check constraint (%s.%s) violatedBEGIN...EXCEPTIONINSERTEXCEPTIONSAVEPOINTWHEN OTHERSNO_DATA_FOUNDSQLCODEWHEN OTHERSSQLCODE = -2290BEFORE INSERT OR UPDATECHECKREGEXP_LIKESELECT ... INTORAISE_APPLICATION_ERRORRAISE_APPLICATION_ERROR(-20001, '邮箱格式错误')IF :NEW.start_date > :NEW.end_date THEN ... END IF;REGEXP_LIKECHECKchk_emp_email_formatsys_c0012345COMMENT ON CONSTRAINTCOMMENT ON CONSTRAINT chk_emp_email_format IS '要求含@和域名,不校验MX记录';DISABLE NOVALIDATEALTER TABLE ... ENABLE VALIDATEORA-02293IF NOT REGEXP_LIKE(:p_email, '^[^@]+@[^@]+\.[^@]+$') THEN RAISE_APPLICATION_ERROR(-20002, '邮箱格式非法');INSERTEXCEPTIONORA-02290AUTONOMOUS_TRANSACTIONIFRAISE