核心概念先理清
MySQL触发器是附着在表上的数据库对象,当表发生INSERT、UPDATE、DELETE操作时,会自动触发预设的逻辑,不需要额外调用。存储过程是一组预编译的SQL语句集合,支持参数传递、条件判断、循环等编程逻辑,需要通过CALL语句手动调用。

触发器的基础特性
触发器分为BEFORE和AFTER两种触发时机,分别对应操作执行前和执行后触发。每个触发器只能关联一张表,且一张表最多可以有6个触发器,对应三种操作的两个时机。触发器的优势是自动执行,不需要业务层干预,适合做数据校验、关联表自动更新等场景。
存储过程的基础特性
存储过程支持输入参数、输出参数,内部可以使用DECLARE声明变量,用IF、CASE做条件分支,用WHILE、REPEAT做循环逻辑,还能处理异常。存储过程适合封装复杂的多步SQL操作,一次调用就能完成一系列关联操作,减少业务层和数据库的交互次数。
组合应用的核心思路
两者的组合核心逻辑是:用触发器作为自动触发的入口,在触发器内部调用封装好的存储过程,把复杂的业务逻辑放到存储过程中实现,触发器只做触发动作的识别和参数传递。
这种设计有两个明显优势:一是业务逻辑集中在存储过程中,后续修改逻辑只需要更新存储过程,不需要修改触发器;二是触发器保持轻量,只负责触发动作,不会因为逻辑过于复杂影响表的DML操作性能。
实战场景:订单状态同步与日志记录
假设我们有订单表order_info、订单操作日志表order_log、用户积分表user_point,需求是:当用户下单后,自动记录订单创建日志,同时给用户增加对应订单金额的10%作为积分;当订单状态更新为已发货时,自动记录发货日志,同时给用户发送积分提醒(这里用打印信息模拟)。
第一步:创建基础表结构
-- 订单表
CREATE TABLE order_info (
order_id INT PRIMARY KEY AUTO_INCREMENT,
user_id INT NOT NULL,
order_amount DECIMAL(10,2) NOT NULL,
order_status VARCHAR(20) NOT NULL DEFAULT '待支付',
create_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
update_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
);
-- 订单操作日志表
CREATE TABLE order_log (
log_id INT PRIMARY KEY AUTO_INCREMENT,
order_id INT NOT NULL,
log_content VARCHAR(255) NOT NULL,
create_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP
);
-- 用户积分表
CREATE TABLE user_point (
user_id INT PRIMARY KEY,
total_point INT NOT NULL DEFAULT 0,
update_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
);
第二步:创建存储过程封装业务逻辑
先创建处理订单创建后逻辑的存储过程,接收订单ID和用户ID、订单金额作为参数:
DELIMITER //
CREATE PROCEDURE proc_order_create(
IN p_order_id INT,
IN p_user_id INT,
IN p_order_amount DECIMAL(10,2)
)
BEGIN
DECLARE v_point INT;
-- 计算新增积分,订单金额的10%,取整
SET v_point = FLOOR(p_order_amount * 0.1);
-- 插入订单创建日志
INSERT INTO order_log (order_id, log_content)
VALUES (p_order_id, CONCAT('订单创建成功,订单ID:', p_order_id));
-- 更新用户积分,如果用户不存在则插入初始积分
INSERT INTO user_point (user_id, total_point)
VALUES (p_user_id, v_point)
ON DUPLICATE KEY UPDATE total_point = total_point + v_point;
END //
DELIMITER ;
再创建处理订单状态更新为已发货的存储过程:
DELIMITER //
CREATE PROCEDURE proc_order_deliver(
IN p_order_id INT,
IN p_user_id INT
)
BEGIN
-- 插入发货日志
INSERT INTO order_log (order_id, log_content)
VALUES (p_order_id, CONCAT('订单已发货,订单ID:', p_order_id));
-- 模拟发送积分提醒,实际场景可对接消息队列
SELECT CONCAT('用户', p_user_id, '的订单', p_order_id, '已发货,当前积分已更新') AS remind_msg;
END //
DELIMITER ;
第三步:创建触发器调用存储过程
创建订单表插入后的触发器,自动调用订单创建的存储过程:
DELIMITER //
CREATE TRIGGER tri_order_after_insert
AFTER INSERT ON order_info
FOR EACH ROW
BEGIN
-- 调用订单创建的存储过程,传递新插入的订单数据
CALL proc_order_create(NEW.order_id, NEW.user_id, NEW.order_amount);
END //
DELIMITER ;
创建订单表更新后的触发器,当订单状态更新为已发货时,调用发货处理的存储过程:
DELIMITER //
CREATE TRIGGER tri_order_after_update
AFTER UPDATE ON order_info
FOR EACH ROW
BEGIN
-- 只有当订单状态从其他状态变为已发货时才触发
IF OLD.order_status != '已发货' AND NEW.order_status = '已发货' THEN
CALL proc_order_deliver(NEW.order_id, NEW.user_id);
END IF;
END //
DELIMITER ;
第四步:验证组合效果
插入一条订单数据,验证自动触发逻辑:
-- 插入订单 INSERT INTO order_info (user_id, order_amount) VALUES (1001, 299.50); -- 查看订单表数据 SELECT * FROM order_info WHERE user_id = 1001; -- 查看订单日志 SELECT * FROM order_log; -- 查看用户积分 SELECT * FROM user_point WHERE user_id = 1001;
执行后会发现,订单插入成功后,order_log表自动生成了创建日志,user_point表中用户1001的积分增加了29(299.5*0.1取整为29)。
再更新订单状态为已发货,验证更新触发逻辑:
-- 更新订单状态为已发货 UPDATE order_info SET order_status = '已发货' WHERE order_id = 1; -- 查看订单日志 SELECT * FROM order_log; -- 查看提醒信息 -- 之前调用存储过程时已经返回了提醒内容,也可以再次查询日志确认
执行后order_log表会新增发货日志,同时会返回积分提醒的消息,实现了完整的自动化流程。
注意事项与优化建议
- 触发器内部调用的存储过程不要有太复杂的耗时操作,避免阻塞表的DML操作,影响业务性能。
- 存储过程的异常处理要做好,比如插入日志失败、更新积分失败时,要明确是回滚操作还是记录异常日志,避免数据不一致。
- 如果业务场景需要跨库操作,存储过程中可以封装跨库的SQL逻辑,触发器只需要传递参数即可,不需要关心跨库细节。
- 定期清理无用的触发器和存储过程,避免过多的数据库对象增加维护成本。
这种组合方案适合业务逻辑相对稳定、不需要频繁修改的场景,如果业务逻辑经常变化,建议还是把核心逻辑放在业务层实现,数据库层只做基础的数据存储和校验。
MySQLtriggerstored_procedureautomation_control修改时间:2026-06-24 09:18:50