16 触发器
概念
触发器trigger是一种特殊类型的存储过程。
触发器主要是通过事件进行触发而被执行,而存储过程是可以直接通过存储过程的名字被调用执行
触发器的作用
1、 可以在写入数据表前,强制检验或转换数据,以保证数据安全
2、 触发器发生错误时,异动的结果会被撤销
如果触发器执行发生错误,那么前面执行成功的操作也会被撤销,类似事务安全
3、 部分数据库管理系统可以针对数据定义语言DDL使用触发器,称为DDL触发器
优缺点
优点
1、 触发器可通过数据库中的相关表实现级联更改
如果某张表的数据改变,可以利用触发器来实现其他表的无痕操作
2、 对数据进行安全校验,保证数据的安全
缺点
1、 对触发器的依赖,会影响数据库的结构,同时增加了维护的复杂程度
2、 在php层,会造成数据在程序层不可控
创建触发器
create trigger 触发器名称 触发时机 触发事件 on 表 for each row
beign
-- 操作体
end
触发对象
触发对象:就是 on 表 for each row,触发器绑定的对象的实质就是表中的所有行,当发生指定条件的改变时,就会触发触发器
触发时机
每张表中对应的行都会有不同的状态,当sql指令发生的时候,都会使表中的行的数据发生变化,每一行的数据变化会有2种状态:数据操作前和数据操作后
before:表中数据发生改变前的状态
after:表中数据发生改变后的状态
触发事件
在mysql中触发器主要针对的目标是数据的改变,所以其所对应的操作只有写操作:增删改
**insert:插入操作
update:更新操作
delate:删除操作**
注意事项
一张表中,每一个触发时机绑定的触发事件所对应的触发器只能有一个:即一张表中只能有一个对应 after insert的触发器。
因为,一张表中最多也之只能有6个触发器:
before insert
before update
brfore delete
after insert
after update
after delete
查看触发器
查看全部触发器
show triggers;
查看触发器创建语句
show create trigger 触发器名称;
触发/使用触发器
触发器会根据触发事件自动执行:即当触发器指定的事件发生时,会自动执行触发器
记录关键字 new 和 old
触发器针对的目标是数据表中的每行记录,每行记录在操作前后都会有一个对应的状态,而触发器在触发之前就将对应的状态记录保存到old关键字中,将操作后的状态放到new关键字中
在触发器中,可以通过old和new关键字来获取绑定表中对应的记录数据。
关键字.字段名
注意:
old和new 并不是所有触发器都有
insert:插入前全是控,没有old
delate:清空数据,没有new
update:new 和 old 都有
删除触发器
drop trigger 触发器名称;
应用:商品自动扣除库存 的触发器
需求:有2张表,商品表和订单表(保留商品id),每次订单生成后,商品表中对应商品的库存都会发生变化
1. 创建 商品表和订单表
-- 商品表
create table product(
id int PRIMARY key auto_increment COMMENT '主键id',
name VARCHAR(20) not null COMMENT '商品名称',
inv int COMMENT '库存'
);
-- 订单表
CREATE table orders(
id int PRIMARY key auto_increment COMMENT '订单id',
orderNo VARCHAR(50) not null COMMENT '订单号',
orderNum int not null COMMENT '商品数量',
pid int COMMENT '商品id',
FOREIGN key(pid) REFERENCES product(id) -- 设置pid为外键
);
2. 产品表插入数据
INSERT INTO product VALUES(null,'手机',100),
(null,'电脑',80),
(null,'平板',50),
(null,'耳机',60),
(null,'数据线',32),
(null,'鼠标',50),
(null,'鼠标垫',10);
SELECT * from product;
创建触发器
1. 触发器1-订单表插入数据前:校验商品库存是否足够,否则不可以下单
-- 创建一个触发器:订单表orders,在生成订单之前,需要校验指定商品的库存是否>0,否则就不能下单
CREATE TRIGGER tr_before_insert_order BEFORE INSERT on orders for each ROW
BEGIN
DECLARE newInv int default 0; -- 定义一个变量 保存指定商品的库存
-- 获取对应的商品库存
SELECT inv into newInv from product WHERE id = new.pid;
-- 如果下单数 大于 库存,不可以下单
if newInv < new.orderNum THEN
-- 中断操作,不可以下单:暴力主动报错
INSERT into XXX VALUES();
end if;
END
2. 触发器2:-订单表插入数据后:在订单表中,每新增一条数据,产品表中对象的商品库存就减少对应的数量:自动扣除库存
-- 创建一个触发器,在订单表中,每新增一条数据,产品表中对象的商品库存就减少对应的数量:自动扣除库存
CREATE TRIGGER tr_after_insert_order AFTER INSERT on orders for EACH ROW
BEGIN
-- 更新对应的商品库存 new对应的orders表
UPDATE product set inv=inv-new.orderNum WHERE id=new.pid;
END
触发触发器
向订单表中插入数据
-- 订单表执行insert操作,会自动触发触发器,产品表中对应的产品库存-1
INSERT INTO orders VALUES(null,'2024107191652DJKUI',3,7);
SELECT * from orders;
SELECT * from product;
注意:当商品表中的库存不足时,再次向订单表中插入数据,会报错