存储过程是预编译的sql语句集合,存储在数据库中,通过call调用执行,支持参数传递、事务控制和错误处理;触发器是特殊存储过程,在insert/update/delete事件发生时自动执行,分before/after时机,仅支持行级触发。

直接调用存储过程并检查返回结果
测试存储过程最直接的方式是用 CALL 执行它,再查表或输出参数是否符合预期。关键不是“有没有报错”,而是“业务逻辑是否被准确执行”。
- 必须提前准备好测试数据:比如转账存储过程,得先插入两个账户,且余额足够;触发器测试则要准备能触发条件的 INSERT/UPDATE/DELETE 操作
- 如果存储过程有
OUT或INOUT参数,要用变量接收:SET @result = 0; CALL calc_total(1, @result); SELECT @result; - 注意事务隔离:默认自动提交,但若过程内含
START TRANSACTION,测试完记得ROLLBACK避免污染测试环境 - 别只测“成功路径”:故意传入非法值(如负金额、不存在的 ID),确认错误处理逻辑(
DECLARE EXIT HANDLER)是否生效
用 BEFORE/AFTER 触发器验证数据变更前后的状态
MySQL 只支持行级触发器(FOR EACH ROW),且不支持语句级触发。这意味着你不能靠“触发次数”判断逻辑对错,而必须检查每行数据在触发前后的实际变化。
-
BEFORE触发器里改NEW字段,要立刻验证:执行INSERT后查表,确认字段是否被修正(比如工资低于 4000 自动设为 4000) -
AFTER触发器常用于日志写入,测试时必须查日志表是否新增对应记录,且OLD/NEW值与原始操作一致 - 避免在触发器里调用存储过程或修改同表数据——这会引发
Can't update table 'xxx' in stored function/trigger错误 - 用
SHOW TRIGGERS LIKE 'xxx';确认触发器已启用,状态为ENABLED
模拟并发场景暴露竞态问题
单条 CALL 测试通过不代表生产安全。存储过程和触发器在高并发下容易因锁机制或未加事务导致数据不一致。
- 用脚本并发调用同一存储过程(如 10 个线程同时转账),检查最终余额总和是否守恒
- 触发器若依赖
SELECT查询其他行做判断(比如库存扣减),必须加SELECT ... FOR UPDATE,否则可能超卖 - 注意
autocommit设置:默认开启,但存储过程内部显式START TRANSACTION时,外部调用者需控制提交时机 - 临时表或用户变量(
@var)在并发下不安全,局部变量(DECLARE var INT)才是线程隔离的
调试时绕过权限和语法陷阱
很多“测试失败”其实和逻辑无关,而是环境配置或语法细节导致的。
- 命令行客户端必须用
DELIMITER $$切换结束符,否则;会让 MySQL 在BEGIN处就终止解析,报ERROR 1064 - 存储过程名区分大小写取决于系统变量
lower_case_table_names,测试脚本里统一用小写更稳妥 - 触发器无法调试,也没有
PRINT语句,临时替代方案是往日志表INSERT调试信息,但上线前必须删掉 -
information_schema.ROUTINES和information_schema.TRIGGERS是唯一可靠元数据来源,别信SHOW PROCEDURE STATUS的模糊匹配











