本文主要基于Mysql数据库的InnoDB存储引擎介绍事务相关知识。
1.先来说说数据库引入事务的目的。
事务是数据库系统区别于文件系统的重要特性之一。
早期计算机程序通过文件系统的编程接口来进行数据管理,在使用过程中有很多不方便的地方,比如数据很容易冗余,数据格式和读写的应用程序绑定紧密,不方便共享;需要程序自己保证数据的一致性等等。所以后来基于文件系统的处理思想封装了关系型的数据库,通过统一标准的数据库接口访问数据。在文件系统处理场景下,如果需要更新两个文件,更新完一个文件后,再跟新另一个文件之前操作系统重启,那么就会有两个不同的数据文件。这正是数据库系统引入事务的主要目的:事务会把数据库从一种一致性状态转化为另外一种一致性状态。在数据库系统提交时,可以保证所有的修改都已经保存了,要么所有的修改都不保存。
2. 在ISO/IEC 10026-1:1992规范中说明数据库管理系统(DBMS)中事务所具有的四个特性:ACID。对于Mysql的InnoDB存储引擎而言,其默认的事务隔离级别是Read Repeatable,完全满足事务的ACID特性。
A:atomicity(原子性):就是用户当前的操作视为一个整体,要么都做,要么都不做.
C:consistency(一致性):一致性指事务将数据库从一种一致性状态转变为下一种一致性状态。在事务的开始之前和结束之后,数据库的约束条件没有被破坏,比如说唯一约束,主键约束等,还需要满足数据库设计者心中的隐式约束。
I:isolation(隔离性):隔离性描述的是每个读写事务的对象与其他事务操作的对象不互相影响,也就是说当前事务提交前对其他事务不可见。(可以想想事务的隔离级别就是描述的隔离性)
D:durability(持久性):即事务提交之后,数据的更新结果是永久性的。即使此时发生了宕机等事故,数据库也能将数据恢复。
3.事务的分类:
事务的分类
3.1 扁平事务
这是我们在实际生产中使用最频繁的事务,也是我们使用中最简单的一种。开启事务时直接使用begin,使用rollback来回滚事务,使用commit来提交事务。需要注意的是,在事务结束前(commit/rollback),这期间的执行都是原子性的,要么都执行,要么都回滚。
扁平事务
扁平事务存在的问题是当需要回滚时,只能将全部操作回滚,这样的话在使用中开销有些大。在有些场景里,我们期望将操作回滚到某一个状态,比如我开启的扁平事务里操作了A,B,C三张表,当操作C表出现问题时,在当前的扁平事务场景里,对A,B,C的操作会全部回滚。而我期望的只是将对表C的操作进行回滚。
3.2 带有保存点(savepoint)的扁平事务
带有保存点(savepoint)的扁平事务除了支持扁平事务外,还允许事务执行过程中回滚到当前事务中指定的状态上,指定的事务状态可以由savepoint来设置。
带有保存点的扁平事务
Savepoint记录了事务在某个点的状态,这样当发生错误进行回滚时,事务能找到当时的数据状态。带保存点的扁平事务模型解决了某些事务可能在执行过程中出现错误并不会导致所有的操作无效的问题,就像上边的扁平事务,在执行失败后会将操作全部回滚,这样有些简单粗暴且开销太大。
其实扁平事务本身也是隐式的设置了一个Savepoint,只是这个保存点设置在了事务开始之时,在整个事务中,只有这一个保存点。
3.3 链事务
链事务可以认为是保存点模式的一个变种。保存点事务模型存在的问题是:保存点并不是持久化在磁盘上的,而是在内存中。当数据库服务器发生宕机时,所有的保存点将会消失。这也就意味着当进行数据恢复时,事务需要从开始处重新执行,不再从最近的保存点继续执行。链事务的核心思想:在提交事务时,释放不需要的数据对象,将必要的处理上下文隐式的传给下一个要开始的事务。需要注意的是,提交事务操作和开始下一个事务操作都是原子性的。
链式事务模型
链事务与带有保存点的扁平事务的区别:带有保存点的扁平事务可以回滚到任意正确的保存点,而链事务中的回滚仅限于当前事务,即只能恢复到最近一个保存点。链事务在执行Commit后即释放了当前事务所持有的锁,而带有保存点的扁平事务不影响迄今为止所持有的锁。
3.4 嵌套事务
嵌套事务是一个层次结构框架。需要由一个顶层事务控制着各个层次的事务,顶层事务之下的嵌套事务被称为子事务。嵌套事务可以理解为若干事务组成的一棵树,子树既可以是扁平事务,也可以是嵌套事务。处于事务树上叶节点的事务是扁平事务。
嵌套事务模型
嵌套事务的一个使用场景:事务方法A调用事务方法B,外层调用方法和内层被调用的方法都是事务方法。
3.5 分布式事务
分布式事务的另一种说法就是跨库(跨实例)事务。比如我们以前的账户系统里,账户余额和账户记录的生成在不同的实例下边,在更新账户余额的时候需要同步的去记录更新的明细,这就是典型的分布式事务的场景。
比如典型的支付场景里,扣款时会有以下两步(1)创建订单;(2)更新账户余额; 因为订单库和账户库有可能在不同的数据库实例里,所以扣款操作需要访问网络中两个数据库节点,这里就会牵扯到了分布式事务。
用户扣款模型图
分布式事务的场景下,要访问不同网络节点下的数据库,每个节点的数据库执行的都是扁平事务。对于分布式事务,其同样需要满足ACID的特性,要么全部成功,要么全部失败。
文章主要介绍了当前主流的Mysql数据库在InnoDB存储引擎下支持的事务,但文章里边还有些坑没填,比如事务的实现原理,savepoint的作用和原理等,改天再开一篇聊聊这些。











网友评论