MySQL事务必须显式执行START TRANSACTION才能启用ROLLBACK;默认autocommit=1时每条语句自动提交,DECLARE HANDLER无法回滚未开启的事务,且嵌套过程中的COMMIT会提前终结外层事务。

必须显式写 START TRANSACTION,不能只靠 DECLARE HANDLER
MySQL 默认 autocommit=1,每条语句单独提交。哪怕你写了 DECLARE EXIT HANDLER FOR SQLEXCEPTION,只要没配 START TRANSACTION,ROLLBACK 就无事务可滚——这是最常被忽略的前提。
-
BEGIN ... END不是事务起始,它只是语句块;写BEGIN代替START TRANSACTION是无效的 - 事务必须在
HANDLER声明之前、实际 DML 操作之前开启,顺序错乱会导致 handler 捕获异常时已脱离事务上下文 - 嵌套调用其他存储过程时,若子过程自己执行了
COMMIT,会提前提交外层整个事务,后续ROLLBACK直接失效
用 EXIT HANDLER 而不是 CONTINUE HANDLER 做主事务回滚
CONTINUE HANDLER 捕获异常后继续往下走,容易漏掉 ROLLBACK 或误执行 COMMIT;EXIT HANDLER 一触发就跳出当前 BEGIN ... END 块,更适合“出错即停、立刻回滚”的主流程控制。
面向 CRM 系统的 MySQL 8 数据库模式设计。当用户需要为客户关系管理(CRM)系统设计、评审、优化或生成数据库模式时,应使用此项技能。
-
EXIT HANDLER内必须立即写ROLLBACK,且推荐紧接在BEGIN后,避免 handler 执行完就退出、后续语句(比如COMMIT)仍被执行 - 不要只在 handler 里设变量(如
SET t_error = 1)却不ROLLBACK,那等于没防护 - handler 中加
RESIGNAL可原样抛出原始错误(含 SQLSTATE 和 MESSAGE_TEXT),但要求 MySQL ≥ 5.7.2;低于该版本会报语法错误
错误类型要选准:SQLEXCEPTION vs SQLWARNING
SQLEXCEPTION 捕获真正中断执行的错误(如主键冲突、列不存在、数据截断失败),而 SQLWARNING 只捕获警告(如隐式类型转换、字段值被截断),后者默认不触发 EXIT HANDLER。
- 业务上需要对警告也做回滚时,得单独声明
DECLARE EXIT HANDLER FOR SQLWARNING,或改用GET DIAGNOSTICS主动检查 - 想精准拦截某类错误(如唯一键冲突),可用
DECLARE EXIT HANDLER FOR SQLSTATE '23000'或错误码1062 - 别用
FOR SQLWARNING代替FOR SQLEXCEPTION,否则主键冲突这类致命错误会被放过
嵌套调用时事务控制权实际在最外层过程
MySQL 不支持真正的嵌套事务。如果过程 A 调用过程 B,而 B 自己写了 START TRANSACTION 和 COMMIT,B 的 COMMIT 会把 A 开启的整个事务一起提交掉——A 后续即使出错,ROLLBACK 也无事务可滚。
- 所有子过程应避免自行开启/提交事务,只做纯 DML 操作,由最外层统一管控
- 若必须复用带事务逻辑的子过程,应将其改为接受事务状态参数(如
IN p_in_transaction TINYINT),由调用方决定是否跳过START TRANSACTION - 排查时可查
information_schema.INNODB_TRX,看事务是否意外提前结束或长时间挂起
START TRANSACTION、handler 内真实执行了 ROLLBACK、没有被内层 COMMIT 提前破坏事务边界——缺一不可。

















