触发器是与表有关的数据库对象,在满足定义条件时触发,并执行触发器中定义的语句集合。触发器的这种特性可以协助应用在数据库端确保数据的完整性。
13.1 创建触发器
CREATE
[DEFINER = user]
TRIGGER trigger_name
trigger_time trigger_event
ON tbl_name FOR EACH ROW
[trigger_order]
trigger_body
trigger_time: { BEFORE | AFTER }
trigger_event: { INSERT | UPDATE | DELETE }
trigger_order: { FOLLOWS | PRECEDES } other_trigger_name
触发器只能创建在永久表(Permanent Table)上,不能对临时表(Temporary Table)或试图创建
触发器。
在触发器主体内,您可以使用别名OLD和NEW来引用主题表(与触发器关联的表)中的列。OLD.col_name在更新或删除之前引用现有行的列。NEW.col_name指向要插入的新行或更新后的现有行的列。换句话说,在INSERT触发器中,只能使用NEW.col_name。没有旧的行。在DELETE触发器中,只能使用OLD.col_name。没有新行。在UPDATE触发器中,可以使用OLD.col_name来引用更新前的行的列,并可以使用NEW.col_name来引用更新后的行的列。
示例:创建一个insert动作相关的触发器与表关联,在向账户表插入数据前,累加金额。
create table account(acct_num int, amount decimal(10,2));
# 定义触发器,在向表account插入数据时,累计金额
create trigger ins_sum before insert on account
for each row set @sum = @sum + NEW.amount;
set @sum=0;
INSERT INTO account VALUES(137,14.98),(141,1937.50),(97,-100.00);
SELECT @sum AS 'Total amount inserted';
+-----------------------+
| Total amount inserted |
+-----------------------+
| 1852.48 |
+-----------------------+
从MySQL5.7.2开始,可以为给定表定义具有相同触发事件和动作事件的多个触发,这在之前是不允许的,只能通过begin...end
复合块来执行多个动作。例如,一个表可以有两个BEFORE UPDATE触发器。默认情况下,具有相同触发事件和动作时间的触发将按照其创建顺序进行激活。要影响触发顺序,请在FOR EACH ROW之后指定一个子句,该子句指示FOLLOWS或PRECEDES,以及一个现有触发器的名称,该触发器也具有相同的触发器事件和动作时间。使用FOLLOWS,新触发器将在现有触发器之后激活。使用PRECEDES,新触发器将在现有触发器之前激活。
例如,在表account的基础上在定义before insert的触发器
set @depositis=0;
set @withdraw=0;
create trigger ins_transaction before insert on account
for each row precedes ins_sum
set
@depositis = @depositis + if(NEW.amount>0,New.amount,0),
@withdraw = @withdraw + if(NEW.amount<0,-NEW.amount,0);
select @depositis '存款', @withdraw '取款', @sum '总额';
+-----------------------+
| 存款 | 取款 | 总额 |
+-----------------------+
| 1952.48 | 100 |1852.48|
+-----------------------+
此触发器ins_transaction与ins_sum类似,但分别存储存款和取款。它有一个PRECEDES子句,使它在ins_sum之前激活;如果没有该子句,它将在ins_sum之后激活,因为它是在ins_sum之后创建的。
以OLD命名的列是只读的。您可以引用它(如果您具有SELECT特权),但不能对其进行修改。如果您具有使用SELECT特权,则可以引用以NEW命名的列。在BEFORE触发器中,如果您具有UPDATE(insert、update)特权,也可以使用SET NEW.col_name = value更改其值。这意味着您可以使用触发器来修改要插入到新行中或用于更新行的值。(这种SET语句在AFTER触发器中无效,因为行更改已经发生。)
示例:在更新account表时检查账户入账金额。
delimiter //
create trigger upd_check before update on account
for each row
begin
if NEW.amount < 0 then
set NEW.amount = 0;
elseif NEW.amount > 100 then
set NEW.amount = 100;
end if;
end
//
优势:分别定义存储过程,然后使用简单的CALL语句从触发器调用存储过程会更容易。如果要在多个触发器中执行相同的代码,这也将非常有利。
13.2 删除触发器
drop trigger trigger_name;
If you drop a table, any triggers for the table are also dropped.
13.3 查看触发器
SHOW TRIGGERS
[{FROM | IN} db_name]
[LIKE 'pattern' | WHERE expr];
show triggers from db
like 'acc%'; # like后是表名