MySQL触发器里怎么写多条SQL语句
MySQL触发器默认只允许单条语句,直接写多个
INSERT、
UPDATE或
SET会报错:
ERROR 1064(语法错误)。必须用
BEGIN ... END块包裹,并显式声明分隔符。 先用
DELIMITER $$临时改分隔符,避免与触发器体内的分号冲突 触发器体必须用
BEGIN和
END包裹,中间每条语句以分号结尾 定义完触发器后,记得恢复分隔符:执行
DELIMITER ;
示例:
DELIMITER $$ CREATE TRIGGER after_order_insert AFTER INSERT ON orders FOR EACH ROW BEGIN INSERT INTO order_logs(order_id, action, created_at) VALUES (NEW.id, 'created', NOW()); UPDATE inventory SET stock = stock - NEW.quantity WHERE item_id = NEW.item_id; UPDATE users SET total_spent = total_spent + NEW.amount WHERE id = NEW.user_id; END$$ DELIMITER ;
触发器里能调用存储过程吗
可以,但要注意权限和事务行为。调用存储过程是组织复杂逻辑的常用方式,尤其当多个触发器需要复用同一组操作时。
确保当前用户对目标存储过程有EXECUTE权限 存储过程内部的事务行为会受触发器所在事务影响——如果触发器回滚,调用的存储过程也会回滚 不能在触发器中调用含
COMMIT或
ROLLBACK的存储过程,否则报错:
ERROR 1305: SAVEPOINT does not exist建议把业务逻辑抽到存储过程中,触发器只做轻量调度,便于测试和维护
多个操作失败时触发器会怎样回滚
整个触发器语句属于原 SQL 事务的一部分。只要其中任意一条语句失败(如违反外键、唯一约束、字段溢出),整个触发器中断,且**原 DML 操作也会被回滚**——这是 MySQL 的默认行为(严格模式下)。
例如INSERT INTO t1触发器里执行了两条
UPDATE,第二条因
NULL插入非空字段失败 → 整个
INSERT失败,t1 不插入,两条
UPDATE都不生效 无法在触发器内捕获异常或做局部回滚(MySQL 8.0 之前不支持
DECLARE HANDLER在触发器中使用) 如果需要容错,得提前校验(如用
IF EXISTS或
SELECT ... INTO判断状态),而不是依赖事后捕获
触发器执行多个操作有哪些隐藏风险
最容易被忽略的是性能和递归问题。看似简单的几行语句,在高并发或大数据量场景下可能成为瓶颈或死锁源。
每个触发器操作都会加额外行锁/表锁,多条UPDATE可能延长事务持有锁时间,加剧锁等待 如果触发器修改的表又触发了另一个触发器(比如 A 表触发器更新 B 表,B 表也有触发器),默认开启
innodb_lock_wait_timeout下可能超时,或配置
max_sp_recursion_depth不足导致报错:
ERROR 1420: Recursive stored function or trigger invocation is not allowed日志体积剧增:每条触发语句都记入 binlog,复制延迟可能变大;审计类写入(如日志表)没加索引的话,
INSERT本身就会变慢 调试困难:触发器无显式调用入口,出问题时需查
SHOW TRIGGERS、检查错误日志、甚至临时禁用触发器排查
真正难的不是写多条语句,而是预判它们在真实负载下的连锁反应。尤其是跨表更新+未加索引的日志表+主从延迟敏感场景,往往要上线后才暴露。
