Oracle触发器可在BEFORE INSERT/UPDATE中用PL/SQL实现数据校验,通过:new访问值、raise_application_error中断执行,禁用跨库调用与大表查询,优先使用内置函数,复杂逻辑应外置配置表。
oracle触发器本身不能直接执行复杂业务规则校验逻辑,但可以在 before insert/update 触发器中用纯 pl/sql 实现绝大多数常见校验——只要不碰跨库调用、远程 http、文件读写或未授权 java。
BEFORE INSERT/UPDATE 触发器是校验主战场
这是唯一能真正阻止非法数据入库的时机。AFTER 触发器无法 rollback 原始 DML,只能补救或报错(但此时数据已落库)。关键点在于使用 :new 伪记录访问待插入/更新值,并用 raise_application_error 中断执行。
- 必须加
FOR EACH ROW,否则拿不到单行:new值 - 校验逻辑要放在
BEGIN ... END;内,不能只写裸 IF - 错误码必须是
-20000到-20999范围内的负整数,比如-20001 - 避免在触发器里查其他大表——会拖慢所有 INSERT/UPDATE,尤其高并发场景
复杂校验别硬写 SQL,优先用内置函数组合
Oracle 提供了足够多的字符串、正则、日期工具,不用自己手撕逻辑。例如身份证校验第 17 位奇偶性、邮箱域名白名单、密码强度,都可以用 REGEXP_LIKE + SUBSTR + INSTR 拆解完成。
-
REGEXP_LIKE(:new.email, '^[a-zA-Z0-9._%+-]+@(?i)(company\.com|partner\.org)$')—— 域名白名单 -
LENGTH(:new.password) >= 8 AND REGEXP_LIKE(:new.password, '[a-z]') AND REGEXP_LIKE(:new.password, '[A-Z]') AND REGEXP_LIKE(:new.password, '[0-9]')—— 密码基础强度 - 避免用
UTL_HTTP或UTL_FILE:这些需要显式授权,且极易超时或引发 ORA-06512
真要调 Java 存储过程?先过这三关
不是不行,但每一步都可能卡住。只有当 PL/SQL 确实无法表达逻辑(比如调用加密 SDK 或复杂数学库)时才考虑这条路。
- Java 方法必须是
public static,参数/返回值只能是 Oracle 映射类型,如java.lang.String、int、java.sql.Date - 类必须用
loadjava -u user/pass@db -r -v加载,漏掉-r(resolve)会导致状态为 INVALID,查USER_OBJECTS就能看到 - PL/SQL 包装过程声明里的 name 字符串,大小写、包路径、括号空格必须和 Java 源码完全一致,例如
'com.example.Validator.check(java.lang.String)'
容易被忽略的性能与递归陷阱
触发器一旦写进生产表,就变成所有 DML 的必经之路。一个看似无害的 SELECT COUNT(*) FROM audit_log WHERE ... 在每秒上千次插入时就是瓶颈。
- 禁止在触发器里修改当前表(比如
UPDATE target_table SET x = y WHERE id = :new.id),会触发递归,除非加PRAGMA AUTONOMOUS_TRANSACTION并明确 COMMIT - 所有查询尽量走索引字段,WHERE 条件别写
UPPER(:new.name) = 'ABC'这种无法走索引的写法 - 如果校验逻辑随业务频繁变更,别把规则硬编码进触发器——改一次就要 DBA 执行 DDL,建议把规则存到配置表,触发器只做简单 SELECT + 判断


















