MySQL存储过程必须显式声明DECLARE CONTINUE HANDLER FOR SQLEXCEPTION才能捕获SQL异常并继续执行日志写入,否则异常导致后续语句照常运行、事务不回滚;它仅捕获MySQL内部错误(如主键冲突、除零),不捕获业务逻辑判断失败。

MySQL存储过程不写异常处理器,就等于没做异常处理——SQL失败后既不中断后续语句,也不自动回滚事务,业务逻辑大概率跑飞。
必须用 DECLARE CONTINUE HANDLER FOR SQLEXCEPTION
MySQL不支持逐行 try-catch,只能在 BEGIN...END 块内声明一个全局异常处理器。只声明 EXIT HANDLER 不够:它会直接退出块,INSERT INTO log_table 根本不会执行。
-
CONTINUE是唯一能让你捕获异常后继续执行日志写入的类型 - 一个
BEGIN...END块里只能有一个SQLEXCEPTION处理器,重复声明报错 - 它只捕获 MySQL 内部抛出的错误(如主键冲突、除零、字段超长),不捕获
IF balance 这类业务判断失败
GET DIAGNOSTICS CONDITION 1 是提取错误详情的唯一方式
只声明 HANDLER 不会自动提供错误码或消息。不调用 GET DIAGNOSTICS,你拿到的全是 NULL。
- 必须紧跟在
HANDLER的BEGIN块内调用,且只能取最近一次触发的异常(CONDITION 1) - 常用字段:
MYSQL_ERRNO(如 1062)、RETURNED_SQLSTATE(如 '23000')、MESSAGE_TEXT - 必须先
DECLARE变量接收,例如:DECLARE code INT DEFAULT 0;、DECLARE msg TEXT;
日志表不是可选配件,而是必需基础设施
没有日志表,HANDLER 捕获到的错误就彻底丢失。而且插入日志本身可能因权限或事务问题失败,形成静默丢弃甚至死循环。
- 表结构至少含:
error_procedure_name、error_code、error_message、error_timestamp - 建议日志表用
ENGINE=MyISAM,或在 HANDLER 内显式START TRANSACTION+COMMIT - 确保执行用户对日志表有
INSERT权限,否则 HANDLER 自身会因权限错误再次触发异常
别混淆 SQLSTATE 和 MySQL 错误码
DECLARE HANDLER 只认 SQLSTATE 字符串(如 '23000'),写 FOR 1062 直接语法错误。
- '23000':主键/唯一键冲突、外键约束失败
- '22003':数值越界(如 TINYINT 插 256)
- '22012':除零、NULL 参与算术运算
- 自定义
SIGNAL抛出的异常(如SIGNAL SQLSTATE '45000')需单独声明 handler,FOR SQLEXCEPTION捕不到
最常被忽略的是:DDL 语句(如 ALTER TABLE)会隐式提交事务,前面的 INSERT 就无法回滚;MyISAM 表不支持事务,写了 ROLLBACK 也无效——这些细节不验证,异常处理就是纸糊的。


















