必须用 START TRANSACTION + DECLARE EXIT HANDLER FOR SQLEXCEPTION 成对出现才能确保异常时自动回滚并透传错误;仅声明 handler 无事务则 ROLLBACK 无效,仅开启事务无 handler 则出错后继续执行;handler 必须为 EXIT 类型、位于 BEGIN...END 内且优先按 SQLSTATE 精确捕获(如 '23000'、'22003'),禁用数字错误码;ROLLBACK 和 RESIGNAL 必须显式书写,且 RESIGNAL 置于 handler 末尾;MyISAM 表和 DDL 语句会破坏事务,须全用 InnoDB 并避免事务中执行 DDL。

不加 DECLARE HANDLER 就等于没处理异常——SQL失败后继续执行,事务不会自动回滚,调用方收不到错误,业务逻辑大概率错乱。
必须用 START TRANSACTION + DECLARE EXIT HANDLER FOR SQLEXCEPTION 才能触发回滚
仅声明 EXIT HANDLER 但没开事务,handler 会执行,ROLLBACK 却无效;仅开事务但没 handler,出错后语句照常执行,事务卡在“未提交”状态。
-
START TRANSACTION和DECLARE EXIT HANDLER FOR SQLEXCEPTION必须成对出现,且 handler 必须在BEGIN ... END块内、START TRANSACTION之前或之后(但不能在它中间) - handler 类型必须是
EXIT:触发后立刻退出当前BEGIN ... END块,天然阻断后续 SQL 执行 -
CONTINUEhandler 不适合主事务流控制——它捕获后继续执行,你得手动检查状态、显式IF exit_flag THEN ROLLBACK; END IF;,极易遗漏
不能只写 SQLEXCEPTION,优先按 SQLSTATE 精确捕获
DECLARE EXIT HANDLER FOR SQLEXCEPTION 是兜底方案,但会掩盖错误类型,导致无法区分可恢复冲突(如主键重复)和不可恢复错误(如除零、越界)。
面向 CRM 系统的 MySQL 8 数据库模式设计。当用户需要为客户关系管理(CRM)系统设计、评审、优化或生成数据库模式时,应使用此项技能。
- 用
SQLSTATE '23000'捕获主键/唯一键冲突、外键约束失败,适合记录日志 + 返回友好提示 - 用
SQLSTATE '22003'捕获数值越界(如向TINYINT插入 256),应提前校验输入 - 用
SQLSTATE '22012'捕获除零或NULL参与算术运算,需加IF col IS NOT NULL THEN ...或设默认值 -
DECLARE EXIT HANDLER FOR 1062会直接报语法错误——MySQL 的 handler 只认SQLSTATE字符串,不接受数字错误码
ROLLBACK 必须显式写,RESIGNAL 强烈建议加上
handler 里只写 ROLLBACK 不够:调用方(比如 Python 的 pymysql)可能收不到原始错误,变成“静默失败”。
-
ROLLBACK必须出现在 handler 内,否则事务不会结束,连接释放时可能被服务端自动回滚,但客户端毫无感知 -
RESIGNAL让原始错误透传到客户端,方便上层捕获具体异常(如pymysql.err.IntegrityError) - 若 handler 中做了日志或补偿操作,
RESIGNAL必须放在最后,否则后续语句不执行 - 示例写法:
DECLARE EXIT HANDLER FOR SQLSTATE '23000' BEGIN INSERT INTO error_log(msg, created_at) VALUES ('Duplicate key', NOW()); ROLLBACK; RESIGNAL; END;
最容易被忽略的底层限制:MyISAM 和 DDL 会让事务失效
哪怕 handler 写得再规范,这两点不验证就形同虚设:
- MyISAM 表不支持事务:
START TRANSACTION和ROLLBACK对它完全无效,必须确认所有涉及表都是 InnoDB - DDL 语句(如
ALTER TABLE、CREATE TABLE、DROP TABLE)会隐式提交当前事务,之后的ROLLBACK无法回退它之前的修改 - 避免在事务块中混用 DML 和 DDL;如需建临时表,改用
CREATE TEMPORARY TABLE(它不触发隐式提交)

















