MySQL事务(2):事务控制

事务控制

  • 事务控制语句
    • 1)常用事务语句
    • 2)差异辨析
    • 3)注意事项
      • 已正确执行语句不会自动回滚
      • rollback to savepoint并非结束事务
  • 隐式提交SQL语句
  • 分布式事务
    • 1)XA事务构成
    • 2)XA事务语法
  • 事务控制不良习惯
    • 1)循环中提交
    • 2)不关注一个事务中语句顺序
    • 3)不关注不同事务访问资源的顺序
    • 4)不关注事务隔离级别
    • 5)混合使用存储引擎

事务控制语句

MySQL默认设置下,事务都是自动提交的,即SQL执行后会立即执行commit操作。

1)常用事务语句

显式的开启一个事务需要使用beginstart transaction或者执行set autocommit=0,通过这些语句停止事务的自动提交。常用的事务控制语句如下,

语句 含义
start transaction、begin 显式开启事务
commit、commit work 提交事务,对数据库的修改成为永久性的
rollback、rollback work 回滚当前事务,撤销正在执行的所有未提交的改变
savepoint identifier 设置一个标识符为identifier的保存点
release savepoint identifier 删除指定的事务保存点,如果该保存点不存在会抛出异常
rollback to identifier 回滚到指定保存点
set transaction 设置隔离级别,InnoDB提供的隔离级别有4种,见锁笔记

2)差异辨析

  • start transaction和 begin
    两个语句都可以显式开启事务,区别在于存储过程。
    在存储过程中,MySQL的分析器会将begin识别为begin ... end,因此在存储过程中只能使用start transaction开启一个事务。
  • commit和 commit work
    都用于提交事务,不同之处在于commit work用于控制事务结束后的行为是chain还是release,如果是chain方式,事务就成了链事务。
    可以通过设置completion_type变量的值来进行控制,默认为0。在这种情况下,commitcommit work是等价的。
    当该变量值为1时,commit work等价于commit work chain,表示立刻开启一个相同隔离级别的事务。
    该变量值为2时,等价于commit work release,事务提交后会自动断开与服务器的连接。
    MySQL事务(2):事务控制_第1张图片
    上方操作完成后,查询表中所有记录,只会得到a=1的一条记录。
    设置completion_type=1,插入a=1后对事务进行提交,插入重复记录2时抛出异常。之后执行rollback操作,只留下一条记录,因为commit work chain后自动开启一个链事务,第二条语句在同一个事务内,所以回滚后a=2并没有插入到数据表中。

3)注意事项

已正确执行语句不会自动回滚

InnoDB的事务是原子的,构成事务的每条语句都会提交,或者所有语句都回滚。一条语句失败并抛出异常时,并不会导致先前已经执行的语句回滚。必须用户自己决定是否对已执行的语句提交或回滚,
MySQL事务(2):事务控制_第2张图片
重复插入值后,并没有将第一次正确执行的语句所做的改变回滚。

rollback to savepoint并非结束事务

rollback to savepoint中虽然有 rollback,但是并不是真正结束事务。执行力rollback to savepoint后也需要显式提交或回滚。
MySQL事务(2):事务控制_第3张图片
通过rollback to savepoint回滚到保存点t2,事务并没有结束,
在这里插入图片描述
再运行 rollback后,事务才完整回滚。

隐式提交SQL语句

下方的SQL语句会产生一个隐式提交操作,即执行完这些语句后,会有一个隐式的commit操作,
MySQL事务(2):事务控制_第4张图片
需要注意truncate table语句是DDL,虽然和对整张表执行delete操作是一样的,但truncate无法回滚。

分布式事务

1)XA事务构成

分布式事务允许多个独立的事务资源参与到一个全局事务中。事务资源通常是关系型数据库系统。使用分布式事务时,InnoDB存储引擎的事务隔离级别必须设置为serializable

XA事务有一个或多个资源管理器、一个事务管理器和一个应用程序组成。

  • 资源管理器:提供访问事务资源的方法,通常一个数据库就是一个资源管理器
  • 事务管理器:协调全局事务中的各个事务,需要与所有资源管理器通信
  • 应用程序:定义事务边界,指定全局事务中的操作

MySQL事务(2):事务控制_第5张图片
分布式事务使用两段式提交

  • 阶段1:所有参与全局事务的节点都开始准备(PREPARE),告诉事务管理器已做好提交准备
  • 阶段2:事务管理器告知资源管理器执行 rollback 或 commit。任何一个节点如果不能被正常提交,则其余所有事务都要回滚。

相比于本地事务,分布式事务多了一次PREPARE操作,待收到所有节点的信息后,再进行提交或回滚。

2)XA事务语法

MySQL数据库XA事务的SQL语法如下,

在这里插入图片描述
MySQL事务(2):事务控制_第6张图片
单节点上运行XA事务的例子,
MySQL事务(2):事务控制_第7张图片

事务控制不良习惯

1)循环中提交

大多数情况下,MySQL都会开启自动提交,如果遇到循环执行的SQL语句,相当于每轮循环中都会进行一次提交。下面两个事务过程的执行时相同的,

  1. 自动提交开启的状态下,显式的在每轮循环中提交
    MySQL事务(2):事务控制_第8张图片
  2. 自动提交开启状态下,未显式在每轮循环中提交
    MySQL事务(2):事务控制_第9张图片
  3. 自动提交开启状态下,存储过程使用start transaction
    MySQL事务(2):事务控制_第10张图片

对上述三个过程进行调用,
MySQL事务(2):事务控制_第11张图片
相比于load1和load2中count次提交,存储过程load3只进行了一次提交。如果对load2的调用过程进行调整也可以达到 load3的效果,
MySQL事务(2):事务控制_第12张图片

2)不关注一个事务中语句顺序

根据两阶段锁,整个事务中涉及的锁,需要等待事务提交时才会释放。同一个事务中,把没锁或锁定范围小的语句先执行,锁定范围大的语句后执行

3)不关注不同事务访问资源的顺序

死锁原因中有两条与不同事务访问资源的顺序有关,

  • 不同线程并发访问同一张表的多行数据,未按顺序访问导致死锁
  • 不同线程并发访问多个表时,未按顺序访问导致死锁

4)不关注事务隔离级别

如果完全不关注业务使用的 MySQL 是什么隔离级别,可能会降低程序的并发能力或者导致死锁。

比如业务场景完全能接受幻读,如果要求更高的 QPS,使用 RR 隔离级别显然不是最好的选择,因此可以改为 RC 隔离级别。而如果业务使用的是 RR 隔离级别,可能由于间隙锁导致死锁(可参考MySQL锁笔记中的例子),因此也应该在程序编写时关注 RR 隔离级别下是否会有间隙锁。

5)混合使用存储引擎

在事务中混合使用事务型(比如 InnoDB)和非事务型(比如 MyISAM)表,如果是正常提交是什么问题。但是,如果该事务回滚了,事务型的表可以正常回滚,而非事务型的表的变更就无法回滚了。这种情况就会导致数据不正常,并且事务最终的结果也难以确定。

你可能感兴趣的:(MySQL)