小心MySQL这个配置可能会让你事务部分提交!!

1、官方定义

innodb_rollback_on_timeout

InnoDB rolls back only the last statement on a transaction timeout by default. If --innodb-rollback-on-timeout is specified, a transaction timeout causes InnoDB to abort and roll back the entire transaction.

官方解释当出现事务等待超时 参数innodb_rollback_on_timeout=off的时候,只会回滚最后一条语句,只有当innodb_rollback_on_timeout=on时才会回滚整个事务。

接下来我们来做实验印证这个问题

2、验证

查看参数innodb_rollback_on_timeout = off

先将innodb_lock_wait_timeout 设小点,避免长时间的等待

set innodb_lock_wait_timeout = 10;

tt表为空表

在session1执行以下语句-- 并不提交

begin;
insert into tt values(1,1);
update t set id2 = 2 where id1 = 1;

在session2执行以下语句 – 并不提交

begin;
set innodb_lock_wait_timeout = 10;
begin;
insert into tt values(2,2);
update t set id2 = 2 where id1 = 1; --此处会等待session1的锁

等待10s后,出现报错

Error Code: 1205. Lock wait timeout exceeded; try restarting transaction

这个时候 先后提交session1与session2

commit;

两个都提交后 我们查看tt表数据

可以看到tt表即有session1的插入数据也有session2的插入数据

我们将innodb_rollback_on_timeout改为on再试
这个参数不能动态设置,我们在参数文件加上
innodb_rollback_on_timeout=on
然后重启mysql

小心MySQL这个配置可能会让你事务部分提交!!-每日运维
参数已为on
清空表数据,重复上面的session1与session2的语句

delete from tt;

重复上面步骤后
表tt只有session1插入的数据,session2因超时已全部回滚

3、总结

innodb_rollback_on_timeout=off 是默认值。如果应用没有很好的catch 错误并显示回滚,很有可能就造成了事务的部份提交,为了安全起见可以将innodb_rollback_on_timeout改为true

4、疑问

很明显当innodb_rollback_on_timeout=off这个默认配置在特殊情况下会造成事务的部份提交,会破坏事务的原子性与一致性。为什么MySQL不把innodb_rollback_on_timeout默认值设为on呢?
难道就像隔离级别默认RR就是为了避免binglog为语句格式的主从重放bug一样。innodb_rollback_on_timeout默认为off也是为了避免某个bug吗?