12.1.1 创建触发器
触发器是由事件触发的操作,这些事件包括INSERT、UPDATE、DELETE事件。触发器是一种特殊的存储过程,它预定义了一些SQL,不用CALL来调用。当指定的事件发生的时候,触发器就会自动执行。
触发器语法:
CREATE TRIGGER trigger_name trigger_time trigger_type ON table_name
FOR EACH ROW trigger_stmt
trigger_name 是触发器的名字
trigger_time 取值为BEFORE和AFTER,表示触发时机。
trigger_type 指触发事件,包括INSERT UPDATE DELETE
trigger_stmt 可以编写存储过程,比如 SET @result = NEW.字段。 NEW代表刚才更新或者插入的记录。
触发器用来满足一些复杂的业务需要,比如根据客户当前的账户状态,判断是否允许插入新的订单。
-- 下面的触发器定义的意思是:
-- 在table_name表执行UPDATE操作之前,先往t_operation表中插入一条记录,再执行更新的SQL
CREATE TRIGGER trigger_name BEFORE UPDATE ON table_name
FOR EACH ROW
BEGIN
INSERT INTO t_operation(..) VALUES(..);
END
首先准备3张表,存钱记录表t_take_in、取钱记录表t_take_out与银行余额表t_bank。
现在需求:假设银行余额现在有500,即t_bank表中有一条记录,金额属性为500。如果往t_take_in表中插入一条记录,意味着存了一笔钱。如果往取钱记录表t_take_out表中插入一条记录,意味着取了一笔钱。例如,往存钱记录表t_take_in插入一条金额为100的记录,即又存了100,那么银行余额表t_bank的金额属性应该为600。再往取钱记录表t_take_out中插入一条金额为200的记录,意味着取了200,那么银行余额表t_bank的金额属性应该剩余400。
DROP TABLE IF EXISTS t_take_in;
CREATE TABLE t_take_in -- 存钱记录表
(
id INT(11) PRIMARY KEY AUTO_INCREMENT,
money DECIMAL(5,2), -- 存入金额
inDate DATETIME DEFAULT NOW() -- 存入时间
);
DROP TABLE IF EXISTS t_take_out;
CREATE TABLE t_take_out -- 取钱记录表
(
id INT(11) PRIMARY KEY AUTO_INCREMENT,
money DECIMAL(5,2), -- 支出金额
outDate DATETIME DEFAULT NOW() -- 支出时间
);
再创建一个账户表。我的打算是这样的,假设账户表中已经有了一定的钱。向“存钱记录表t_take_in”中存放钱,将会触发余额表的触发器,让它更新"银行余额表t_bank"。同样,在"取钱记录表t_take_out"中插入数据,意思是当前用户取出了一笔钱,那么也用触发器,同步更新"银行余额表t_bank"。
DROP TABLE IF EXISTS t_bank;
CREATE TABLE t_bank
(
money DECIMAL(5,2)
);
INSERT INTO t_bank(money) VALUES(500);
下面开始创建触发器。
DELIMITER //
CREATE TRIGGER addMoney AFTER INSERT ON t_take_in -- 为存钱表加入AFTER INSERT触发器
FOR EACH ROW
BEGIN
UPDATE t_bank SET MONEY = MONEY + NEW.money; -- 存钱表存钱后触发更新,NEW代表刚才更新或者插入的记录。
END //
DELIMITER ;
DELIMITER //
CREATE TRIGGER useMoney AFTER INSERT ON t_take_out -- 在取钱记录表上创建AFTER INSERT触发器
FOR EACH ROW -- 即当t_take_out出现INSERT语句的时候,执行下面的SQL
BEGIN
UPDATE t_bank SET MONEY = MONEY - NEW.money; -- NEW代表刚才更新或者插入的记录。
END //
DELIMITER ;
-- 现在向存钱表里面存钱
INSERT INTO t_take_in(money) VALUES(100);
查看各个表的情况。
存钱记录表t_take_in表里面多了刚才插入的记录。
最关键的"账户表t_bank"的情况,我们来看看。从500变成了600,说明触发器中的SQL执行了。
再来测试一下向"取钱记录表t_take_out"中插入数据,即新增一笔取款记录。
-- 现在向取钱表里面取钱,取200块,账户表预期剩余600-200 = 400元
INSERT INTO t_take_out(money) VALUES(200);
取钱记录表t_take_out表里应该新增一条记录。新增取款200块。
账户表t_bank应该预期为400。
与预期一致,说明触发器设置成功。
拨云见日
原来触发器也不是什么神秘的东西,它是一种特殊的存储过程,它预定义了一些SQL语句。当其它表发生增删改事件的时候,它就会被触发,执行预定义的SQL。
从设计模式的角度来看待,它其实就是一种观察者设计模式。从Java的角度来看待,它就是一个监听器。触发器触发后将会执行定义好的SQL语句。
12.1.2 查看触发器
所有的触发器都存放在information_schema数据库中的triggers表中。
SELECT * FROM information_schema.`TRIGGERS` WHERE TRIGGER_NAME LIKE '%Money%'
第二种方法就是最常用的方法:SHOW TRIGGERS;
SHOW TRIGGERS;
12.1.3 删除触发器
DROP TRIGGER IF EXISTS useMoney;
-- 补充删除视图的方法
DROP VIEW IF EXISTS view_name;
12.1.4 专家解惑
惑而不从师其为惑也终不解矣。
能不能创建两个相同事件的触发器?
比如能否在同一张表上创建两个 BEFORE INSERT 触发器?答案是不可以。此时,只可以在这张表上创建其它的触发器,比如 AFTER INSERT,BEFORE UPDATE。
结论:相同事件只能创建一个触发器。
表结构发生更改,触发器会自动删除吗?
表结构发生更改,不会自动删除触发器,除非删除了这张表,触发器会自动被删除。
如果因为需求的变化,旧的触发器没有被及时手动删除的话,旧的触发器将会照常工作,可能会影响数据完整性,因此需要手动删除。DROP TRIGGER trigger_name;
阅读更多
如果本文对你有帮助,不妨请我喝瓶可乐吧!
你的打赏是对我最好的支持!