带你看看事务的分类和在MySQL中使用链式事务 | SQL全面教程七:事务(3)事务分类和MySQL中的commit work and chain
本篇主要参考自《MySQL技术内幕:innodb存储引擎》、维基百科、相关官方文档等内容。
事务分类
从形式上,事务分为以下几类。
- 扁平事务(
Flat Transactions
) - 带有保存点的扁平事务(
Flat Transactions with Savepoints
) - 链式事务(
Chained Transactions
) - 嵌套事务(
Nested Transactions
) - 分布式事务(
Distributed Transactions
)
当然还有多级事务(Multilevel Transactions
)。
事务的这种分类,也可以描述为事务的模型(models),即不同模型的事务。
扁平事务
扁平事务是最常见的一种。扁平事务中所有操作都处于同一层次,由Start Transaction
/BEGIN WORK
开始,由commit [work]
或rollback [work]
结束,期间的操作时原子的,要么都执行、要么都不执行。
扁平事务三种不同的结果,分别是commit,rollback,等待超时。扁平事务的主要限制是不能提交或者回滚一部分,或者分几步提交。
带有保存点的扁平事务
除了支持扁平事务外,还能在事务的回滚中回滚到一个较早的状态。
保存点(Savepoint)用来系统记录当前事务的状态,以便发生错误时,事务能回滚到保存点当时的状态。SAVEPOINT savepoint_name;
或save work
命令设置保存点。
扁平事务默认有一个保存点1,也就是事务开始的地方。
链事务
在提交一个事务时,释放不需要的数据对象,将必要的处理上下文隐式地传给下一个要开始的事务。注意:提交事务操作和下一个事务开始操作合并为一个原子操作,这意味着下一个事务将看到上一个事务的结果。
链事务的工作方式如下图所示:
链事务只能回滚当前事务,即恢复到最近的一个事务开始点。链事务在执行commit操作后即释放了当前事务持有的锁。而带有保存点的扁平事务在创建保存点时不影响迄今为止持有的锁。
链事务可以看作保存点模式的一种变种,带保存点的扁平事务,当发生系统崩溃或故障时,所有的保存点都会消失,因为保存点是易失的(
volatile
),而非持久的(persistent
)。这表示,当进行恢复需要重做日志时,事务需要从开始处重新执行,而无法从最近的一个保留点继续执行。
链事务是串行执行的,有着特定的顺序。
嵌套事务(Nested transactions)
嵌套事务是一个层次结构框架,由一个顶层事务(top-level transaction)控制着各个层次的事务。顶层事务之下嵌套的事务称为子事务(subtransaction)。
嵌套事务层次结构图如下图所示:
- 嵌套事务是由若干事务组成的一棵树,子树既可以是嵌套事务,也可以是扁平事务
- 处在叶节点的事务是扁平事务。
- 处于根节点的事务为顶层事务,其他称为子事务。事务的前驱(predecessor)为父事务(parent),事务的下一层称为子事务(child)。
- 子事务既可以提交也可以回滚。但它的提交不会立马生效,除非其父事务提交。因此,任何子事务都在顶层事务提交后才真正的提交。
- 树中任意一个事务的回滚会引起它的所有子事务一同回滚,故子事务仅保留A、C、I特性,不具有D的特性。
在最外层事务提交之前,任何不相关的事务都不会看到更改。这意味着内部事务中的提交不一定会将更新持久化到系统中。
即使一个RDBMS不支持嵌套事务,也可以通过保留点来模拟嵌套事务。但是,当通过保留点模拟嵌套事务时,用户无法选择哪些锁需要被子事务继承,哪些需要被父事务保留。而嵌套事务中,不同子事务在数据库对象上持有的锁是不同。
MySQL的InnoDB不支持嵌套事务,PostgreSQL也不支持嵌套事务。
嵌套事务提供了真正基于组件的应用程序架构的能力。组件函数可能包含也可能不包含数据库事务,如果在BEGIN-COMMIT括号内调用含事务的组件函数,则会发生嵌套事务。但是由于MySQL等流行数据库不支持嵌套事务,因此需要一个框架或事务监视器(
transaction monitor
)来处理这个问题。
(此部分 无需关注)
- "Closed Nesting" 封闭嵌套:子事务的提交最终依据顶层事务是否提交。SQL Server数据库系统就是这种形式的嵌套。
- "Open Nesting" 开放嵌套:子事务可以独立于父事务进行提交。也就是如果父事务回滚,成功的子事务的结果不会回滚。父事务的提交或回滚,不影响子事务的提交。
分布式事务
分布式事务通常是一个在分布式环境中运行的扁平事务。需要根据数据所在位置访问网络中的不同节点。
(比如,跨行转账,会涉及到分布式事务),分布式事务同样需要满足ACID特性。
InnoDB存储引擎提供XA事务,由此支持分布式事务的实现。
分布式事务指的是允许多个独立的事务资源(transactional resources
,如RDBMS等)参与到一个全局的事务中。这其中涉及到多个独立的资源管理器(resource manager
),通常指数据库,还涉及一个事务管理器(transaction manager
),用于协调管理多个资源尤其是跨服务器资源组成的全局事务。全局事务要求其中所有的事务要么都提交,要么都回滚。
- 资源管理器:用来管理系统资源,是通向事务资源的途径。数据库就是一种资源管理器。资源管理还应该具有管理事务提交或回滚的能力。
- 事务管理器:事务管理器是分布式事务的核心管理者。事务管理器与每个资源管理器进行通信,协调并完成事务的处理。事务的各个分支由唯一命名进行标识。
XA协议由Tuxedo首先提出的,并交给X/Open组织的分布式事务的规范或者协议标准
后续会对分布式事务进行详细介绍。
MySQL的InnoDB原生并不支持嵌套事务,但是支持扁平事务、带保留点的事务、链事务和分布式事务。PostgreSQL不支持嵌套事务。SQL Server支持扁平事务、带保留点的事务、分布式和嵌套事务,但不支持链式事务。
关于多级事务(Multi-level Transactions)
多级事务属于嵌套事务的一种,或者说是嵌套事务的变体。大多数数据库文档或SQL概念中,并没有将其列为特定的技术术语,或在数据库系统中专门实现它。
多级事务是嵌套事务的一种变体,其中子事务发生在分层系统架构的不同级别(例如,一个操作在数据库引擎级别,一个操作在操作系统级别)
Multi-level transactions are a variant of nested transactions where the sub-transactions take place at different levels of a layered system architecture (e.g., with one operation at the database-engine level, one operation at the operating-system level)
具体可以查看 research.microsoft.com/en-us/um/pe… 中的介绍。
关于MySQL中的commit work
、commit work and chain
MySQL/MariaDB中可以使用start transaction
的别名begin work
开启一个事务。
事务提交和回滚除了commit
、rollback
,还可以使用commit work
、rollback work
。默认情况下,加不加work都是等价的。
commit work and chain;
用于开启一个链式事务,即提交的同时开始一个新的事务。
使用START TRANSACTION;
/begin
显式开启一个事务,如果执行commit
会提交事务;如果执行commit work and chain;
则会提交事务并自动启动下一个事务,这样可以省去了再次执行START TRANSACTION;
或begin work
的开销,较少了语句交互的次数,并且也明确标识语句处于事务中。
commit
和commit work
的不同取决于completion_type
参数的设置:completion_type=0
:二者完全等价(也是默认方式),表示提交当前事务。completion_type=1
:commit work
等同于commit and chain
,表示提交当前事务,并马上开启一个相同隔离级别的事务。completion_type=2
:commit work
等同于commit and release
,表示提交事务后会自动断开与服务器的连接。
rollback和rollback work与commit和commit work的执行完全相同。
- 查看
completion_type
参数设置:
MariaDB [(none)]> show variables like 'completion_type';
+-----------------+----------+
| Variable_name | Value |
+-----------------+----------+
| completion_type | NO_CHAIN |
+-----------------+----------+
1 row in set (0.025 sec)
- 设置
completion_type
参数为1:
MariaDB [(none)]> set @@completion_type=1;
Query OK, 0 rows affected (0.008 sec)
MariaDB [(none)]> show variables like 'completion_type';
+-----------------+-------+
| Variable_name | Value |
+-----------------+-------+
| completion_type | CHAIN |
+-----------------+-------+
1 row in set (0.001 sec)
转载自:https://juejin.cn/post/6987373561836994590