1.事务的基本概念
事务一般指的是逻辑上的一组操作,或者作为单个逻辑单元执行的一系列操作。同属于一个事务的操作会作为一个整体提交给系统,这些操作要么全部执行成功,要么全部执行失败。
2.事务的特性
总体来说,事务存在四大特性,分别是:
- 原子性(Atomic)
- 一致性(Consistency)
- 隔离性(Isolation)
- 持久性(Durability)
如下图所示,事务的四大特性又被称为:ACID
2.1 原子性
事务的原子性指的是构成事务的所有操作要么全部执行成功,要么全部执行失败,不可能出现部分执行成功,部分执行失败的情况。
例如,在转账业务中,张三向李四转账 100 元,于是张三的账户余额减少 100 元,李四的账户余额增加 100 元。在开启事务的情况下,这两个操作要么全部执行成功,要么全部执行失败,不可能出现只将张三的账户余额减少 100 元的操作,也不可能出现只将李四的账户余额增加 100 元的操作
2.2 一致性
事务的一致性指的是在事务执行之前和执行之后,数据始终处于一致的状态
例如,同样是转账业务,张三向李四转账 100 元,且转账前和转账后的数据是正确的,那么,转账后张三的账户余额会减少 100 元,李四的账户余额会增加 100 元,这就是数据处于一致的状态。如果张三的账户余额减少了 100 元,而李四的账户余额没有增加 100 元,这就是数据处于不一致状态
2.3 隔离性
事务的隔离性指的是并发执行的两个事务之间互不干扰。也就是说,一个事务在执行过程中不能看到其他事务运行过程的中间状态
例如,在张三向李四转账的业务场景中,存在两个并发执行的事务 A 和事务 B,事务 A 执行扣减张三账户余额的操作和增加李四账户余额的操作,事务 B 执行查询张三账户余额的操作。在事务 A 完成之前,事务 B 读取的张三的账户余额仍然为扣减之前的账户余额,不会读取到扣减后的账户余额
注意:MySQL 通过锁和 MVCC 机制来保证事务的隔离性
2.4 持久性
事务的持久性指的是事务提交完成后,此事务对数据的更改操作会被持久化到数据库中,并且不会被回滚
例如,在张三向李四转账的业务场景中,在同一事务中执行扣减张三账户余额和增加李四账户余额的操作,事务提交完成后,这种对数据的修改操作就会被持久化到数据库中,且不会被回滚
注意:数据库的事务在实现时,会将一次事务中包含的所有操作全部封装成一个不可分割的执行单元,这个单元中的所有操作,要么全部执行成功,要么全部执行失败。只要其中任意一个操作执行失败,整个事务就会执行回滚操作
3.事务的类型
事务主要分为五大类,分别为:
- 扁平事务
- 带有保存点的扁平事务
- 链式事务
- 嵌套事务
- 分布式事务
3.1 扁平事务
扁平事务:是事务操作中最常见,也是最简单的事务。在数据库中,扁平事务通常由 begin 或者 starttransaction 字段开始,由 commit 或者 rollback 字段结束。在这之间的所有操作要么全部执行成功,要么全部执行失败(回滚)。当今主流的数据库都支持扁平事务。
扁平事务虽然是最常见、最简单的事务,但是无法提交或者回滚整个事务中的部分事务,只能把整个事务全部提交或者回滚。为了解决这个问题,带有保存点的扁平事务出现了
3.2 带有保存点的扁平事务
通俗地讲,内部设置了保存点的扁平事务,就是带有保存点的扁平事务。带有保存点的扁平事务通过在事务内部的某个位置设置保存点(savepoint),达到将当前事务回滚到此位置的目的
示例如下:
在 MySQL 数据库中,通过如下命令设置事务的保存点:
savepoint [savepoint_name]
例如,设置一个名称为 save_user_point 的保存点,代码如下所示:
savepoint save_user_point
通过如下命令将当前事务回滚到定义的保存点位置:
rollback to [savepoint_name]
例如,将当前事务回滚到定义的名称为 save_user_point 的保存点位置,代码如下所示:
rollback to save_user_point
通过如下命令删除保存点:
release savepoint save_user_point
从本质上讲,普通的扁平事务也是有保存点的,只是普通的扁平事务只有一个隐式的保存点,并且这个隐式的保存点会在事务启动的时候,自动设置为当前事务的开始位置。也就是说,普通的扁平事务具有保存点,而且默认是事务的开始位置
3.3 链式事务
链式事务:是在带有保存点的扁平事务的基础上,自动将当前事务的上下文隐式地传递给下一个事务。也就是说,一个事务的提交操作和下一个事务的开始操作具备原子性,上一个事务的处理结果对下一个事务是可见的,事务与事务之间就像链条一样传递下去
注意:链式事务在提交的时候,会释放要提交的事务中的所有锁和保存点,也就是说,链式事务的回滚操作只能回滚到当前所在事务的保存点,而不能回滚到已提交事务的保存点
3.4 嵌套事务
嵌套事务就是有多个事务处于嵌套状态,共同完成一项任务的处理,整个任务具备原子性。嵌套事务最外层有一个顶层事务,这个顶层事务控制着所有的内部子事务,内部子事务提交完成后,整体事务并不会提交,只有最外层的顶层事务提交完成后,整体事务才算提交完成
关于嵌套事务需要注意以下几点:
1)回滚嵌套事务内部的子事务时,会将事务回滚到外部顶层事务的开始位置
2)嵌套事务的提交是从内部的子事务向外依次进行的,直到最外层的顶层事务提交完成
3)回滚嵌套事务最外层的顶层事务时,会回滚嵌套事务包含的所有事务,包括已提交的内部子事务
在主流的关系型数据库中,MySQL 不支持原生的嵌套事务,而 SQL Server 支持。不建议使用嵌套事务
3.5 分布式事务
分布式事务指的是事务的参与者、事务所在的服务器、涉及的资源服务器以及事务管理器等分别位于不同分布式系统的不同服务或数据库节点上。简单来说,分布式事务就是一个在不同环境(比如不同的数据库、不同的服务器)下运行的整体事务。这个整体事务包含一个或者多个分支事务,并且整体事务中的所有分支事务要么全部提交成功,要么全部提交失败
例如,在电商系统的下单减库存业务中,订单业务所在的数据库为事务 A 的节点,库存业务所在的数据库为事务 B 的节点。事务 A 和事务 B 组成了一个具备 ACID 特性的分布式事务,要么全部提交成功,要么全部提交失败
4. 本地事务
4.1 基本概念
在常见的计算机系统和应用系统中,很多事务是通过关系型数据库进行控制的。这种控制事务的方式是利用数据库本身的事务特性来实现,而在这种实现方式中,数据库和应用通常会被放在同一台服务器中,因此,这种基于关系型数据库的事务也可以称作本地事务或者传统事务
本地事务使用常见的执行模式,可以使用如下伪代码来表示:
transaction begin
insert into 表名 (字段名列表) values (值列表)
update 表名 set 字段名 = 字段值 where id = id值
delete from 表名 where id = id值
transaction commit/rollback
另外,本地事务也具有一些特征。以下列举几个本地事务具有的典型特征:
1)一次事务过程中只能连接一个支持事务的数据库,这里的数据库一般指的是关系型数据库
2)事务的执行结果必须满足 ACID 特性
3)事务的执行过程会用到数据库本身的锁机制
4.2 本地事务的执行流程
本地事务执行流程如下图所示:
从图中可以看出:
1)客户端开始事务操作之前,需要开启一个连接会话
2)开始会话后,客户端发起开启事务的指令
3)事务开启后,客户端发送各种 SQL 语句处理数据
4)正常情况下,客户端会发起提交事务的指令,如果发生异常情况,客户端会发起回滚事务的指令
5)上述流程完成后,关闭会话
本地事务是由资源管理器在本地进行管理的
4.3 本地事务的优缺点
本地事务的优点总结如下:
1)支持严格的 ACID 特性,这也是本地事务得以实现的基础
2)事务可靠,一般不会出现异常情况
3)本地事务的执行效率比较高
4)事务的状态可以只在数据库中进行维护,上层的应用不必理会事务的具体状态
5)应用的编程模型比较简单,不会涉及复杂的网络通信
本地事务的缺点总结如下:
1)不具备分布式事务的处理能力
2)一次事务过程中只能连接一个支持事务的数据库,即不能用于多个事务性数据库
欢迎来到这里!
我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。
注册 关于