咦,为什么我的事务回滚不了?

2022-01-24 09:47:07 浏览数 (1)

MySQL 事务小伙伴们都懂,通过 begin 开启事务,通过 commit 提交事务或者通过 rollback 回滚事务。

在前面的文章中,松哥也和大家聊了一些事物原理以及相关的细节,小伙伴们可以回顾一下:

  • MVCC 水略深,但是弄懂了真的好爽!
  • 一致性视图是啥时候建立的?
  • 四个案例看懂 MySQL 事务隔离级别

正常来说,当我们开启一个事务之后,需要 commit 或者 rollback 来结束一个事务的,但是有时候,一些操作会自动帮我们提交事务,如果大家不了解隐式事务的话,那么在具体使用事务的事务可能就会遭遇一些莫名其妙的问题。

1. DDL 操作

首先一点就是 DDL 操作会隐式提交事务,这个松哥在之前的文章中其实有说过,我们再来一起回顾下:

❝所有的 DDL 语句都会导致事务隐式提交,换句话说,当你在执行 DDL 语句前,事务就已经提交了。这就意味着带有 DDL 语句的事务将来没有办法 rollback。

我举一个简单的例子,大家一起来看下:

我们来一起看下我这里的测试逻辑:

  1. 首先查询总记录数有四条。
  2. 开启一个事务。
  3. 执行一条删除语句。
  4. alter 表,新增一个字段。
  5. 回滚。
  6. 再次查询数据。

到第六步的时候,我们发现查询到的数据只剩三条了,说明第五步的回滚并没有生效。原因就在于执行 alter 之前,事务已经被隐式提交了。

所以小伙伴们在日常开发中,最好不要在事务中混有 DDL 语句,DDL 语句和 DML 语句分开写。

对于上面的案例,如果大家去掉第四步的 alter,那么回滚是可以回滚成功的,这个小伙伴们自己来测试,我就不演示了。

当然 DDL 操作可不仅仅是 alter,其他的如 CREATE、DROP 等操作也会导致事务隐式提交,这里松哥就不一一举例了,小伙伴们可以自行尝试。

2. DCL 操作

DDL 和 DML 大家应该经常接触到,但是 DCL 可能有小伙伴不清楚,DCL 其实就是 Data Control Language,中文译作数据控制语言,我们日常授权或者回收数据库上的权限所使用的 GRANT、REVOKE 等,就算是 DCL 操作。

我举个简单例子:

可以看到,跟第一小节的测试步骤一样,只不过第四步换成一个 GRANT 语句,那么最终的事务回滚也会失效,原因就在于事务已经提交了。

当然,除了 GRANT 和 REVOKE 之外,其他的创建、更新或者删除用户的操作也会导致事务隐式提交。主要有:

  • CREATE USER...
  • DROP USER...
  • ALTER USER...
  • SET PASSWORD...

3. 新事务开启

一个事务还没提交,结果你又开启了一个新的事务,那么此时前一个事务也会隐式提交。看个例子:

这个好理解,不多说。

4. 各种锁操作

给表上锁、解锁也会导致事务隐式提交。如下:

上锁的 SQL 如 lock tables table_name read|write,会导致事务隐式提交,解锁的 SQL 如 unlock tables 也会导致事务被隐式提交。

除了表锁,一些全局锁如 FTWRL 也会导致事务的隐式提交,如下:

5. 从机的操作

之前松哥有教大家如何大家 MySQL 主从:

  • MySQL8 主从复制踩坑指南

我们在从机上执行的一些操作如 start slavestop slavereset slave 以及 change master to 等语句也会隐式提交事务。

6. 其他表操作

其他的一下操作如刷新权限(flush privileges)、优化表(optimize table)、修复表(repair table)等操作,也会导致事务的隐式提交。

flush privileges 导致事务隐式提交

optimize table 导致事务隐式提交

repair table 导致事务隐式提交

我在网上看有人说 LOAD DATA 会隐式提交事务,松哥亲测貌似并不会,如下图:

LOAD DATA 似乎并没有导致事务隐式提交,欢迎大家提出不同见解一起探讨。

7. 最佳实践

那么多隐式提交,我怎么记得住呀?其实不用背,你只要记着事务里只写增删改查(INSERT/DELETE/UPDATE/SELECT),就不会错啦!

0 人点赞