MySQL 5.7中设置无效enum值为何未触发错误处理程序回滚事务
问题原因分析
- SQL_MODE未在存储过程执行时生效
你在创建存储过程前执行的SET sql_mode = 'STRICT_ALL_TABLES';属于会话级临时配置,不会固化到存储过程的执行逻辑中。如果调用存储过程的会话SQL_MODE没有开启严格模式(STRICT_ALL_TABLES或STRICT_TRANS_TABLES),向ENUM列写入非法值的操作只会触发1265警告而非SQLEXCEPTION,不会触发你定义的异常捕获逻辑。此时存储过程会继续执行后续的COMMIT语句,直接提交了之前的INSERT操作。
即便你调用时确实收到了1265错误提示,也建议检查当前会话的SQL_MODE配置,部分客户端会默认修改会话级SQL_MODE参数。 - test_tran表使用非事务性存储引擎
你建表时没有显式指定ENGINE=InnoDB,如果你的MySQL实例默认存储引擎被修改为MyISAM这类不支持事务的引擎,就算事务正常回滚,MyISAM表的写入操作也不会被撤销,会直接持久化到磁盘。你可以执行SHOW CREATE TABLE test_tran;确认表的实际存储引擎。 - 存在隐式提交事务的场景
如果调用存储过程前的会话已经开启了未提交的事务,或者存储过程中存在DDL类语句(ALTER、CREATE等)会触发隐式事务提交,也会导致写入操作无法回滚,当前你提供的存储过程中没有DDL语句,所以这个场景概率较低。
修复方案
- 将SQL_MODE设置写到存储过程内部的最开头,确保执行时生效:在
START TRANSACTION;前添加SET SESSION sql_mode = 'STRICT_ALL_TABLES'; - 建表时显式指定
ENGINE=InnoDB,确保所有参与事务操作的表都使用事务性存储引擎 - 可以在异常捕获逻辑中增加临时调试语句,确认HANDLER是否被正常触发执行
内容的提问来源于stack exchange,提问作者SnowQuest
相关产品推荐
相关产品推荐

