事务是访问并更新数据库中各种数据的最小单元,在事务的操作中,要么都修改成功,要么都修改失败。它的主要目的是:将数据库从一个一直状态转换成另一种一直状态。
事务的四个特性是:
- 原子性(atomicity):原子性指整个数据库事务是不可分割的工作单位。只有使事务中所有的数据库操作都执行成功,才算整个事务成功。
- 一致性(consistency):一致性指事务将数据库从一种状态转变为下一种一致的状态。
- 隔离性(isolation):隔离性还有其他的称呼,如并发控制(concurrency control)、可串行化(serializability)、锁(locking)等。事务的隔离性要求每个读写事务的对象对其他事务的操作对象能相互分离,即该事务提交前对其他事务都不可见,通常这使用锁来实现。
- 持久性(durability):事务一旦提交,其结果就是永久性的。
事务隔离性由锁来实现,原子性、一致性和持久性是通过数据库的redo log和undolog来实现的。
事务的隔离级别:
-
READ UNCOMMITTED
:未提交读,会产生脏读。 -
READ COMMITTED
:读已提交(不可重复读),会产生幻读,oracl的默认隔离级别。 -
REPEATABLE READ
:可重复读,不会产生换行和脏读,通过MVCC来实现,MySQL的默认隔离级别。 -
SERIALIZABLE
:串行化。
事务的分类
从事务理论的角度来说,可以把事务分为以下几种类型:
- 扁平事务(Flat Transactions)
- 带有保存点的扁平事务(Flat Transactions with Savepoints)
- 链事务(Chained Transactions)
- 嵌套事务(Nested Transactions)
- 分布式事务(Distributed Transactions)
扁平事务(Flat Transactions)
扁平事务事务时最简单的一种事务,也是平时用得最多的一种,在扁平事务中,所有操作都处于同一层次,其由BEGIN WORK
开始,由COMMIT WORK
或ROLLBACK WORK
结束,其间的操作是原子的,要么都执行,要么都回滚。
带有保存点的扁平事务(Flat Transactions with Savepoints)
除了支持扁平事务支持的操作外,允许在事务执行过程中回滚到同一事务中较早的一个状态。这是因为某些事务可能在执行过程中出现的错误并不会导致所有的操作都无效,放弃整个事务不合乎要求,开销也太大。
保存点(Savepoint)用来通知系统应该记住事务当前的状态,以便当之后发生错误时,事务能回到保存点当时的状态。其实扁平事务就是只有一个保存点的事务。
image.png当发生回滚是只有执行一次ROLLBACK WORK:7
命名表示回滚到保存点7的位置,如果还需要回滚需要继续执行ROLLBACK WORK:x
命令(x表示保存点编号),带有保存点的扁平事务能回滚到任意正确的保存点。
带保存点事务的保存点是非持久化的,所以当系统崩溃时保存点就会丢失,这时系统恢复时,事务需要从头开始,从新执行。为了解决这个问题提出了链事务。
链事务(Chained Transactions)
链事务是在提交一个事务时,释放不需要的数据对象,将必要的处理上下文隐式地传给下一个要开始的事务。
image.png链事务有个缺点就是当需要回滚事务的时候,只能恢复到最近的一个保存点。
嵌套事务(Nested Transactions)
嵌套事务是一个层次结构框架。由一个顶层事务(top-leveltransaction)控制着各个层次的事务。顶层事务之下嵌套的事务被称为子事务(subtransaction),其控制每一个局部的变换。
image.png嵌套事务特性:
- 子事务可以是嵌套事务,也可以是扁平事务。
- 最后叶子节点的事务一定是扁平事务。
- 子事务的提交并不会立即生效,只有等到顶层事务提交后子事务才会真正提交。
- 任意一个子事务的回滚都会导致所有子事务的回滚。
分布式事务(Distributed Transactions)
在分布式环境下运行的扁平事务,因此需要根据数据所在位置访问网络中的不同节点。分布式事务的常用解决方案有2pc(两段式提交)、3pc(三段式提交)、TCC(Try、Confirm、Cancel)和基于消息的最终一致性。
分布式事务的大致实现思想都是引入一个事务管理器(协调者)来管理参与者服务的事务,由事务管理器来统一调度参与服务的事务到底是提交还是回滚。
InnoDB实现了XA协议,使用了2pc(两段式提交)的方式来实现了分布式事务。
InnoDB存储引擎支持扁平事务、带有保存点的事务、链事务、分布式事务。不支持嵌套事务。
2pc(两段式提交)
原理
image.png第一阶段是表决阶段,由事务管理者(协调者)来发发起事务,并询问所有参与者是否可以提交事务。
第二阶段是执行阶段,协调者收到所有参与者的反馈,根据反馈的结果决定所有参与者是commit
还是rollback
。
优点
- 原理简单
- 实现方便
缺点
- 同步柱塞,当参与1先完成第一阶段的时候,需要阻塞等待参与者2的处理。
- 单点故障,协调者存在单点故障,一点挂掉可能导致参与者一直阻塞。
- 数据不一致,当参与者1收到了commit消息,但是参与者2并没收到的时候就会存在数据不一致的情况。
- 容错机制不完善,还是协调者挂了后会导致所有参与者同步阻塞。
3pc(三段式提交)
三阶段提交,也叫三阶段提交协议,是二阶段提交(2PC)的改进版本,主要是在协调者和参与者之间都引入了超时机制;在第一阶段和第二阶段中插入一个准备阶段。保证了在最后提交阶段之前各参与节点的状态是一致的。
原理
image.png第一阶段,由事务管理者(协调者)来发发起事务,并询问所有参与者是否可以提交事务,这一步非常快速,不会操作数据库。
第二阶段,协调者询问是否可以提交事务,并询问所有参与者是否可以提交事务,这一步才会真正操作数据库。
第三阶段,协调者收到所有参与者的反馈,根据反馈的结果决定所有参与者是commit
还是rollback
,如果超时还是没有收到反馈这时也提交事务。
优点
- 改善同步阻塞的范围,如果超时会中断事务。
- 改善单点故障,最后一步如果协调者挂掉,参与者也会提交事务。
缺点
- 同步柱塞,还是存在同步阻塞的问题,只是引入了超时机制,阻塞问题得到了一定的改善。
- 单点故障,还是有单点故障,只是有超时机制,这个问题得到了一定的改善。
- 数据不一致,当参与者1收到了commit消息,但是参与者2并没收到的时候就会存在数据不一致的情况。
- 容错机制不完善,与2pc相比有一定的改善。
TCC(Try、Confirm、Cancel)
TCC 其实就是采用的补偿机制,其核心思想是:针对每个操作,都要注册一个与其对应的确认和补偿(撤销)操作,TCC本质上也是一个两阶段提交。它分为三个阶段:
-
Try 阶段主要是对业务系统做检测(一致性)及资源预留(准隔离性)。
-
Confirm 阶段主要是对业务系统做确认提交,Try阶段执行成功并开始执行 Confirm阶段时,默认 Confirm阶段是不会出错的,即:只要Try成功,Confirm一定成功。Confirm操作需要满足幂等性。
-
Cancel 阶段主要是释放Try阶段预留的业务资源,该阶段也需要保证幂等。
优点
跟2PC比起来,实现以及流程相对简单了一些,但数据的一致性比2PC也要差一些
缺点
缺点还是比较明显的,在2,3步中都有可能失败。TCC属于应用层的一种补偿方式,所以需要程序员在实现的时候多写很多补偿的代码,在一些场景中,一些业务流程可能用TCC不太好定义及处理。
分布式事务框架Seata
https://github.com/seata/seata
https://mp.weixin.qq.com/s/Xh2jfZgD7Qallh_DAUbeVg
不好的事务习惯
- 在循环中提交事务,循环中提交事务有两个问题:1、性能问题;2、当程序出现异常,数据不能全部回滚。
- 使用自动提交和回滚,在编写应用程序开发时,最好把事务的控制权限交给开发人员,即在程序端进行事务的开始和结束。
- 使用长事务,使用长事务当系统发生故障时,重新开始一个事务的代价比较大;长事务还会长期占用MySQL资源,导致其他操作无法及时的去执行。
网友评论