Java事务总结

Java事务总结

 

事务的特性

事务拥有以下四个特性,习惯上被称为ACID特性:

  1. 原子性(Atomicity):事务作为一个整体被执行,包含在其中的对数据库的操作要么全部被执行,要么都不执行。

  2. 一致性(Consistency):事务应确保数据库的状态从一个一致状态转变为另一个一致状态。一致状态是指数据库中的数据应满足完整性约束。除此之外,一致性还有另外一层语义,就是事务的中间状态不能被观察到(这层语义也有说应该属于原子性)。

  3. 隔离性(Isolation):多个事务并发执行时,一个事务的执行不应影响其他事务的执行,如同只有这一个操作在被数据库所执行一样。

  4. 持久性(Durability):已被提交的事务对数据库的修改应该永久保存在数据库中。在事务结束时,此操作将不可逆转。

 

数据库事务的四种隔离级别

  1. 读未提交(Read Uncommitted)

    事务A可以看见事务B还没提交的所有中间状态

  2. 读提交(Read Committed, RC)

    事务A只能看见事务B提交之后的结果和提交前的结果,看不见中间的变化

  3. 可重复读(Repeated Read, RR)

    事务B在一次操作中,读取的值都是一样的,不会因为事务A中间的操作提交而改变看到的结果

  4. 串行化(Serializable)

    要求所有事务串行,一个个来。

Spring的事务

spring事务的传播行为

所谓事务的传播行为是指,如果在开始当前事务之前,一个事务上下文已经存在,此时有若干选项可以指定一个事务性方法的执行行为。

TransactionDefinition.PROPAGATION_REQUIRED:如果当前存在事务,则加入该事务;如果当前没有事务,则创建一个新的事务。这是默认值。 TransactionDefinition.PROPAGATION_REQUIRES_NEW:创建一个新的事务,如果当前存在事务,则把当前事务挂起。 TransactionDefinition.PROPAGATION_SUPPORTS:如果当前存在事务,则加入该事务;如果当前没有事务,则以非事务的方式继续运行。 TransactionDefinition.PROPAGATION_NOT_SUPPORTED:以非事务方式运行,如果当前存在事务,则把当前事务挂起。 TransactionDefinition.PROPAGATION_NEVER:以非事务方式运行,如果当前存在事务,则抛出异常。 TransactionDefinition.PROPAGATION_MANDATORY:如果当前存在事务,则加入该事务;如果当前没有事务,则抛出异常。 TransactionDefinition.PROPAGATION_NESTED:如果当前存在事务,则创建一个事务作为当前事务的嵌套事务来运行;如果当前没有事务,则该取值等价于TransactionDefinition.PROPAGATION_REQUIRED。

 

 

 

分布式事务

 

BASE理论

  • 基本可用(Basically Available):指分布式系统在出现故障时,允许损失部分的可用性来保证核心可用。

  • 软状态(Soft State):指允许分布式系统存在中间状态,该中间状态不会影响到系统的整体可用性。

  • 最终一致性(Eventual Consistency):指分布式系统中的所有副本数据经过一定时间后,最终能够达到一致的状态。

 

柔性事务

在业内,主要用来解决分布式事务的方案是使用柔性事务。所谓柔性事务,相比较与数据库事务中的ACID这种刚性事务来说,柔性事务保证的是“基本可用,最终一致。”这其实就是基于BASE理论,保证数据的最终一致性。

 

事务补偿操作可以帮助达到最终一致性

提到事务,为了保证原子性,就可能发生commit和rollback,那么在分布式事务中,要想进行rollback,就需要提供可补偿操作。回滚事务时使用,,补偿操作同时也需要满足幂等性。

 

两阶段提交2PC

两阶段提交协议 (Two-phase commit protocol,2PC)的过程涉及到协调者和参与者。协调者可以看做成事务的发起者,同时也是事务的一个参与者。对于一个分布式事务来说,一个事务是涉及到多个参与者的。具体的两阶段提交的过程如下:

第一阶段(准备阶段)

  • 协调者节点向所有参与者节点询问是否可以执行提交操作(vote),并开始等待各参与者节点的响应。

  • 参与者节点执行询问发起为止的所有事务操作,并将 Undo 信息和 Redo 信息写入日志。(注意:若成功这里其实每个参与者已经执行了事务操作)

  • 各参与者节点响应协调者节点发起的询问。如果参与者节点的事务操作实际执行成功,则它返回一个“同意”消息;如果参与者节点的事务操作实际执行失败,则它返回一个“中止”消息。

 

第二阶段(提交阶段)

 

如果协调者收到了参与者的失败消息或者超时,直接给每个参与者发送回滚(Rollback)消息;否则,发送提交(Commit)消息;参与者根据协调者的指令执行提交或者回滚操作,释放所有事务处理过程中使用的锁资源。(注意:必须在最后阶段释放锁资源)

 

  • 当协调者节点从所有参与者节点获得的相应消息都为“同意”时:

协调者节点向所有参与者节点发出“正式提交(commit)”的请求。

参与者节点正式完成操作,并释放在整个事务期间内占用的资源。

参与者节点向协调者节点发送“完成”消息。

 

  • 如果任一参与者节点在第一阶段返回的响应消息为”中止”,或者 协调者节点在第一阶段的询问超时之前无法获取所有参与者节点的响应消息时:

协调者节点向所有参与者节点发出”回滚操作(rollback)”的请求。

参与者节点利用之前写入的Undo信息执行回滚,并释放在整个事务期间内占用的资源。

参与者节点向协调者节点发送”回滚完成”消息。

协调者节点受到所有参与者节点反馈的”回滚完成”消息后,取消事务。

协调者节点受到所有参与者节点反馈的”完成”消息后,完成事务

不管最后结果如何,第二阶段都会结束当前事务。

 

二段式提交协议的优缺点:

优点:原理简单,实现方便;

缺点:

  • 同步阻塞问题。执行过程中,所有参与节点都是事务阻塞型的。

  • 单点故障。由于协调者的重要性,一旦协调者发生故障,参与者会一直阻塞下去。尤其在第二阶段,协调者发生故障,那么所有的参与者还都处于锁定事务资源的状态中,而无法继续完成事务操作。

  • 数据不一致。在阶段二中,当协调者向参与者发送 commit 请求之后,发生了局部网络异常或者在发送 commit 请求过程中协调者发生了故障,这回导致只有一部分参与者接受到了 commit 请求。而在这部分参与者接到 commit 请求之后就会执行 commit 操作。但是其他部分未接到 commit 请求的机器则无法执行事务提交。于是整个分布式系统便出现了数据部一致性的现象。

  • 二阶段无法解决的问题:协调者再发出 commit 消息之后宕机,而唯一接收到这条消息的参与者同时也宕机了。那么即使协调者通过选举协议产生了新的协调者,这条事务的状态也是不确定的,没人知道事务是否被已经提交。

 

为了解决两阶段提交协议的种种问题,研究者们在二阶段提交的基础上做了改进,提出了三阶段提交。

 

三阶段提交

三阶段提交协议(Three-phase commit protocol,3PC),是二阶段提交(2PC)的改进版本。与两阶段提交不同的是,三阶段提交有两个改动点:

 

  • 引入超时机制。同时在协调者和参与者中都引入超时机制。

  • 在第一阶段和第二阶段中插入一个准备阶段。保证了在最后提交阶段之前各参与节点的状态是一致的。

 

即 3PC 把 2PC 的准备阶段再次一分为二,这样三阶段提交就有 CanCommit、PreCommit、DoCommit 三个阶段。

 

三阶段提交不会一直持有事务资源并处于阻塞状态。但是这种机制也会导致数据一致性问题,因为,由于网络原因,协调者发送的 abort 响应没有及时被参与者接收到,那么参与者在等待超时之后执行了 commit 操作,这样就和其他接到 abort 命令并执行回滚的参与者之间存在数据不一致的情况。

要彻底从协议层面避免数据不一致,可以采用Paxos或者Raft 算法。

 

TCC模型

TCC 分布式事务模型包括三部分:

  1. 主业务服务:主业务服务为整个业务活动的发起方,服务的编排者,负责发起并完成整个业务活动。

  2. 从业务服务:从业务服务是整个业务活动的参与方,负责提供 TCC 业务操作,实现初步操作(Try)、确认操作(Confirm)、取消操作(Cancel)三个接口,供主业务服务调用。

  3. 业务活动管理器:业务活动管理器管理控制整个业务活动,包括记录维护 TCC 全局事务的事务状态和每个从业务服务的子事务状态,并在业务活动提交时调用所有从业务服务的 Confirm 操作,在业务活动取消时调用所有从业务服务的 Cancel 操作。

一个完整的 TCC 分布式事务流程如下:

  1. 主业务服务首先开启本地事务;

  2. 主业务服务向业务活动管理器申请启动分布式事务主业务活动;

  3. 然后针对要调用的从业务服务,主业务活动先向业务活动管理器注册从业务活动,然后调用从业务服务的 Try 接口;

  4. 当所有从业务服务的 Try 接口调用成功,主业务服务提交本地事务;若调用失败,主业务服务回滚本地事务;

  5. 若主业务服务提交本地事务,则 TCC 模型分别调用所有从业务服务的 Confirm 接口;若主业务服务回滚本地事务,则分别调用 Cancel 接口;

  6. 所有从业务服务的 Confirm 或 Cancel 操作完成后,全局事务结束。

 

TCC与2PC协议比较

TCC位于业务服务层而非资源层

TCC没有单独的准备(Prepare)阶段,Try操作兼备资源操作与准备能力 • Try操作可以灵活选择业务资源的锁定粒度(以业务定粒度)

TCC有较高开发成本

 

参考

4种事务的隔离级别,InnoDB如何巧秒实现?

https://mp.weixin.qq.com/s/x_7E2R2i27Ci5O7kLQF0UA

 

可能是最漂亮的 Spring 事务管理详解

https://juejin.im/user/59fbb2daf265da4319559f3a/posts

 

微服务架构下处理分布式事务的典型方案

https://www.toutiao.com/a6463349625410552334/

 

分布式系统常见的事务处理机制

https://waylau.com/distributed-system-transaction/

 

分布式事务解决方案

https://mp.weixin.qq.com/s/incZZwqKzlsjSsQo5trEOw

 

干货 | 一篇文章带你学习分布式事务

https://mp.weixin.qq.com/s/RDnf637MY0IVgv2NpNVByw

你可能感兴趣的:(java)