必须修改配置文件并重启才能启用innodb_rollback_on_timeout=ON,因其在MySQL 5.7+中为只读变量,SET GLOBAL和SET SESSION均无效;云数据库需通过参数组流程配置并重启实例。

必须改配置文件并重启,SET GLOBAL 会报错,云数据库要走参数组流程
为什么 SET GLOBAL innodb_rollback_on_timeout = ON 总是失败
这不是权限问题,而是该变量在 MySQL 5.7+ 中被明确设为只读。执行 SET GLOBAL innodb_rollback_on_timeout = ON 会直接返回错误:ERROR 1238 (HY000): Variable 'innodb_rollback_on_timeout' is a read only variable。
-
innodb_rollback_on_timeout不支持运行时修改,SET SESSION完全无效——它根本没有会话作用域 - 本地 MySQL 允许改配置后重启,但线上环境(如阿里云 RDS、腾讯云 CDB、AWS RDS)连
SET GLOBAL都禁用,必须通过控制台「参数组」操作 - 即使你本地成功执行了
SET GLOBAL,服务重启后也会恢复默认值OFF,无法持久化
如何正确永久配置 innodb_rollback_on_timeout = ON
编辑 MySQL 配置文件(常见路径:/etc/my.cnf、/etc/mysql/my.cnf 或 /usr/my.cnf),在 [mysqld] 段落下添加:
innodb_rollback_on_timeout = ON
- 修改前建议先校验语法:
mysqld --defaults-file=/etc/my.cnf --validate-config - 保存后必须重启服务才生效:
sudo systemctl restart mysql(或mysqld,取决于 init 系统) - RDS 用户不能改文件,需进入控制台 → 找到对应「参数组」→ 编辑 → 将
innodb_rollback_on_timeout设为ON→ 保存 → 绑定到实例 → 触发重启(部分厂商支持平滑重启,但仍存在短暂不可用) - 某些旧版 RDS 参数组不显示该选项,需先升级参数模板版本
开启 ON 后应用必须自己处理重试和幂等
当 innodb_rollback_on_timeout = ON 时,触发 ERROR 1205 (HY000): Lock wait timeout exceeded 会导致整个事务回滚,而不是仅回滚最后一条语句。
- Spring 的
@Transactional(timeout=)对锁等待超时完全无效——它只控制事务执行时间,不干预行锁等待逻辑 - 真正起作用的是
innodb_lock_wait_timeout(默认 50 秒),它和innodb_rollback_on_timeout必须协同调整 - 应用层必须捕获
ERROR 1205,并实现幂等重试:插入需带唯一约束或 upsert,状态变更需检查当前值,补偿动作要可重复执行 - 若未封装重试(比如没用
@Retryable或手动 try-catch + 重放),错误直接上抛,前端 500、下游调用中断
最易被忽略的一点:这个参数从来不是“开就安全”的独立开关。它必须和 innodb_deadlock_detect = OFF、innodb_lock_wait_timeout = 3 等组合压测验证,否则可能放大锁堆积或引发高频重试风暴。


















