数据库触发器是什么 对于数据库初学者而言,触发器可能显得有些抽象。实际上,你可以将其想象成一个与特定数据表绑定的“自动化哨兵”,其内部封装了一段预先编写好的PL/SQL程序。 这个“哨兵”的职责非常清晰:当它所守护的表上发生指定的数据操作——例如新增记录、更新数据或删除行——时,它就会被立即“激活”
Oracle触发器用法详解与实例解读
时间:2026-05-08
浏览:147
文章目录
数据库触发器是什么
对于数据库初学者而言,触发器可能显得有些抽象。实际上,你可以将其想象成一个与特定数据表绑定的“自动化哨兵”,其内部封装了一段预先编写好的PL/SQL程序。

这个“哨兵”的职责非常清晰:当它所守护的表上发生指定的数据操作——例如新增记录、更新数据或删除行——时,它就会被立即“激活”,并自动执行预设的程序逻辑。整个过程由数据库系统自动完成,无需手动干预。
一个简单的例子可以帮助理解。假设我们希望在每次向员工表(emp)成功插入新数据后,系统能自动给出提示。使用触发器实现此功能的代码大致如下:
create or replace trigger empTrigger after insert on emp
for each row
declare -- 此处声明局部变量
begin
dbms_output.put_line('插入成功!');
end empTrigger;
执行上述代码后,每次对emp表进行INSERT操作时,你都会在输出中看到“插入成功!”的提示,这正是触发器在后台工作的体现。
触发器的核心语法详解
通过基础示例了解触发器后,我们来深入解析其完整的创建语法。掌握语法是灵活定制触发器的关键。
CREATE [OR REPLACE] TRIGGER trigger_name
{BEFORE | AFTER }
{INSERT | DELETE | UPDATE [OF column [, column …]]}
[OR {INSERT | DELETE | UPDATE [OF column [, column …]]}...]
ON [schema.]table_name | [schema.]view_name
[REFERENCING {OLD [AS] old | NEW [AS] new| PARENT as parent}]
[FOR EACH ROW ]
[WHEN condition]
PL/SQL_BLOCK | CALL procedure_name;
语法结构看似复杂,我们可以将其分解为几个关键部分来理解:
触发时机(BEFORE | AFTER)。 这决定了触发器逻辑的执行时间点。“前触发”(BEFORE)在数据操作实际执行之前启动,常用于数据校验或业务规则拦截;“后触发”(AFTER)则在操作执行之后启动,适用于记录日志或进行事后处理。
触发粒度(FOR EACH ROW)。 此选项至关重要,它区分了“行级触发器”与“语句级触发器”。若指定FOR EACH ROW,则为行级触发器:当一条SQL语句影响100行数据时,触发器逻辑会执行100次,即针对每一行触发一次。若省略,则为语句级触发器:无论语句影响多少行,整个操作仅触发一次。在行级触发器中,可以通过:OLD和:NEW来引用某行数据修改前和修改后的值,这对于字段级别的对比非常有用。
REFERENCING子句与WHEN条件。 REFERENCING允许为新旧数据记录定义别名(默认为OLD和NEW)。在触发器代码块中使用这些别名时需加冒号(如:NEW.salary),但在WHEN条件中则无需添加。WHEN子句用于设置更精细的触发条件,只有满足该条件的行才会激活触发器,此子句仅适用于行级触发器。
总而言之,触发器的核心价值在于,能够将与数据变更紧密相关的业务逻辑(如一致性检查、审计追踪)从应用程序中剥离,直接封装在数据库层。这不仅确保了逻辑执行的必然性,也提升了数据操作的可靠性与完整性。
使用触发器的关键注意事项
了解如何创建触发器后,在使用前还需明确其特性和限制,以避免常见问题。
首先,触发器拥有独立的命名空间。这意味着触发器的名称可以与表名、过程名相同而不会产生冲突。但在同一数据库模式(Schema)下,触发器自身的名称必须是唯一的。
更重要的是,DML触发器在使用上存在若干重要限制:
- 代码长度: CREATE TRIGGER语句本身的文本长度不能超过32KB,编写复杂逻辑时需注意。
- SELECT语句: 触发器体内的SELECT语句必须是
SELECT … INTO形式(用于变量赋值),或是用于定义游标的SELECT语句。不能直接执行返回结果集给客户端的查询。 - 事务控制: 这是一个关键限制。触发器中禁止使用COMMIT、ROLLBACK等事务控制语句。同样,被触发器调用的过程或函数中也不允许使用。事务的提交或回滚应由发起原始DML操作的会话来控制。
- 数据类型: 触发器中不能使用LONG或LONG RAW等过时的数据类型。对于LOB(大对象)类型,可以读取:NEW或:OLD中的LOB列值,但不能通过:NEW来修改LOB列中的数据。
牢记这些限制,有助于在设计触发器时更加得心应手,避免运行时出现意外错误。
DML触发器的核心要素
为了更系统地掌握DML触发器,可以从以下几个核心要素来把握:
触发时机: 即前述的BEFORE和AFTER,根据业务逻辑是需要预防还是追溯来选择合适的时机。
触发事件: 指INSERT、UPDATE、DELETE等数据操作。一个触发器可以监听单一事件,也可以用OR组合监听多个事件(注意是“或”关系,而非“与”关系)。
条件谓词: 当触发器监听了多个事件时,如何在代码中区分当前是由哪个事件触发的?这就需要使用Oracle提供的条件谓词:
INSERTING:若当前触发事件是INSERT,则返回TRUE。UPDATING:若当前触发事件是UPDATE,则返回TRUE。还可进一步使用UPDATING(column_name)来判断特定列是否被更新。DELETING:若当前触发事件是DELETE,则返回TRUE。
触发对象: 明确触发器是建立在哪张表或哪个视图之上。
触发类型: 再次强调,是行级触发器还是语句级触发器,这决定了触发器的执行频率以及能否访问:OLD/:NEW数据。
触发条件: 通过WHEN子句设置的附加逻辑表达式。只有行级触发器才能使用此功能,它可以实现更精准的触发控制。
触发器实战应用示例
理论结合实践才能更好掌握。以下是几个在开发中相当常见的触发器应用场景示例。
示例一:业务时间管控
假设公司规定只能在工作日的工作时间内变更员工信息。我们可以创建一个BEFORE INSERT触发器来实现此规则:
create or replace trigger addEmpInfoCheck
before insert on emp_info
declare
begin
if to_char(sysdate, 'day') in ('星期六', '星期日') or
to_number(to_char(sysdate, 'hh24')) not between 9 and 18 then
--禁止insert
raise_application_error(-20001,'非工作时间禁止插入数据!');
end if;
end addEmpInfoCheck;
这里使用了raise_application_error过程,这是在PL/SQL中主动抛出自定义错误的标准方法。需注意,错误号必须介于-20000到-20999之间。
示例二:数据逻辑校验
第二个例子关于薪资调整:调整后的薪资必须高于调整前的薪资。这显然需要在更新每一行时进行判断,因此必须使用行级触发器(FOR EACH ROW),并借助:OLD和:NEW来比较数值:
create or replace trigger checkSalary
before update
on salary_info
for each row
declare -- 若无变量声明,declare可省略
begin
if :new.sal < :old.sal then
raise_application_error(-20002,'涨后的薪水:'|| :new.sal ||'小于涨前的薪水:'||:old.sal);
end if;
end checkSalary;
示例三:基于数值的连锁操作
第三个例子稍复杂:创建一个触发器,当某表的薪资字段被更新且新值超过6000时,自动将该记录的部分信息插入到另一张审计表中:
create table xzw_test(info varchar2(256));
create or replace trigger addData
after update on xzw_test
for each row
declare
begin
if :new.sal > 6000 then
insert into emp_audit values(:new.sal ||'-'|| :new.username ||'-'|| :new.job);
end if;
end addData;
此示例展示了触发器如何实现一种简单的“审计”或“日志”功能,根据数据变化的具体内容自动触发后续操作。
总结
触发器是Oracle数据库中一项功能强大且实用的特性,如同安插在数据表旁的“自动监督员”。合理使用触发器,可以将大量保障数据完整性和业务一致性的逻辑从应用代码下沉至数据库层,使得规则执行更可靠,系统架构更清晰。当然,也需谨记其使用限制,避免过度使用导致系统性能与复杂度问题。希望本文的梳理与示例,能帮助你更扎实地掌握触发器的设计与应用。
实用工具推荐
绿化、压缩、噪点和虚拟水印,自由调节做旧程度。
选择画质和输出格式,预览压缩前后的大小。