mysql存储过程必须用sqlstate声明异常处理器,如'23000',不可用错误码;需根据continue/exit语义选择 handler 类型,exit handler 中须显式 rollback 并 resignal,且注意 myisam 不支持事务、ddl 隐式提交等限制。

MySQL存储过程里不写DECLARE HANDLER,就等于没做异常处理——单条SQL失败不会中断后续语句,也不会自动回滚事务,业务逻辑大概率跑飞。
必须用SQLSTATE,不能用MySQL错误码
MySQL的DECLARE HANDLER只认SQLSTATE字符串(如'23000'),不接受整数错误码(如1062)。写DECLARE EXIT HANDLER FOR 1062会直接报语法错误。
-
'23000'对应主键/唯一键冲突、外键约束失败等完整性错误 -
'22003'对应数值越界(比如TINYINT插256) -
'22012'对应除零、NULL参与算术运算等 - 查完整映射表可执行
SELECT * FROM information_schema.INNODB_TRX配合错误日志反推,但日常开发记住这三个最常用就够了
CONTINUE和EXIT handler的行为差异极大
选错handler类型会导致事务控制完全失控:
-
DECLARE CONTINUE HANDLER FOR SQLEXCEPTION:捕获后继续执行handler之后的语句,适合仅记录日志或设标志位,但必须手动检查并ROLLBACK -
DECLARE EXIT HANDLER FOR SQLEXCEPTION:捕获后立刻退出当前BEGIN...END块,适合搭配START TRANSACTION,能天然防止“部分提交” - 别混用——比如在
EXIThandler里只SET变量却不ROLLBACK,事务就卡在未提交状态,连接释放时可能被自动回滚,但调用方完全感知不到
回滚必须显式调用,且RESIGNAL建议加上
handler里只写ROLLBACK不够,调用方很可能收不到错误信息,变成“静默失败”:
- 必须在
EXIThandler里写ROLLBACK,否则事务不会结束 - 加
RESIGNAL能让原始错误透出到客户端,方便定位(比如Python里能捕获到pymysql.err.IntegrityError) - 示例写法:
DECLARE EXIT HANDLER FOR SQLEXCEPTION BEGIN ROLLBACK; RESIGNAL; END;
- 如果handler里做了自定义日志或补偿操作,
RESIGNAL要放在最后,否则后续语句不执行
最容易被忽略的是:MyISAM表不支持事务,哪怕写了START TRANSACTION和ROLLBACK也无效;还有ALTER TABLE、CREATE TABLE这类DDL语句会隐式提交,导致前面的INSERT无法回滚——这些细节不验证,异常处理就形同虚设。











