写在前边:看过多个博客之后,在此汇总温习一下,仅留作日后复习。如有侵权,请留言或者私信,立刻马上删!!!
参考:java实现分布式事务的三种方案_分布式事务的实现方式_村口张大爷的博客-CSDN博客
事务(transaction)是访问并可能更新数据库中各数据项的一个程序执行单元。由事务开始到事务结束之间的全部操作组成。
事务具有四个特性,原子性、一致性、隔离性和持久性。通常成为ACID。
原子性:是指事务是一个不可分隔的操作单元,无论是本地事务或是分布式事务,均要求在一个事务内的所有操作,要么一起成功,要么一起失败,不允许存在部分成功,部分失败的情况。如果执行过程中发生失败,则需要回滚到事务开始前的状态。
一致性:执行一次事务,要求各个数据项从一个正确的状态转换到另一个正确的状态,要求执行前后的数据是完整的。
隔离性:在一次事务的执行过程中,要求事务锁定的数据操作只存在于该事务中,不影响其他事务的操作,各个事务之间的操作是相互隔离的。只有当前事务提交后,其他事务才能看到当前事务更新的数据。
持久性:事务执行完成后,会对数据做持久化存储,即使发生宕机等情况,数据依旧存在。
脏读:A事务读取到了B事务尚未提交的数据(尚未提交的数据可能发生回滚)。
幻读:范围读取,在同一个事务内相同的条件(age > 10)多次读取到的数据量不一致。
不可重复读:同一个事务内,相同的条件(age = 10)多次读取的数据结果不一致。
未提交读(Read Uncommited):A事务可读取到B事务尚未提交的数据,可导致脏读、幻读、不可重复读。
已提交读(Read commited):A事务可读取B事务已经提交的数据。可能存在A事务执行过程中B事务已经修改完成,并提交了数据。可导致幻读。不可重复读。
可重复读(Repeated Read):可重复读指在同一个事务内,锁定当前事务操作的数据,在这个事务还没有结束之前,不允许其他的事务操作这些数据,避免了脏读,不可重复读。但是仍存在幻读的可能。
可串行化(Serializanle):保证各个事务顺序执行,事务之间互斥,最高的隔离级别,锁表操作。避免了脏读、幻读、不可重复读,但是并发效率低下。
借助关系型数据库来完成事务,关系数据库通常有ACID特性,传统的单体应用通常会将数据存储在一个数据库中,会借助数据库完成事务。
CAP理论是分布式处理的理论基础,分布式系统在设计时只能在一致性、可用性、分区容忍性之中满足其中的两项,无法同时满足。
一致性(Consistency):节点A、B、C都存储了用户数据,要求同一时刻三个节点的数据需要保持一致性。
可用性(Availiability):服务部署A、B、C三个节点,其中一个节点宕机不会影响系统对外提供服务,如果只有一个A节点,当A节点宕机会导致整个系统无法对外提供服务,增加服务节点B、C是为了保证系统的可用性。
分区容忍性(PartitionTolerance):分区容忍性就是允许系统之间通过网络协同工作,分区容忍性要解决由于网络分区导致的数据不完整及无法访问的问题。
CAP组合方式:CA、CP、AP
CA:放弃分区容忍性,保证数据的可用性和强一致性,关系型数据库按照CA设计。
CP:放弃可用性,加强一致性和分区容忍性,一些强一致性需求要求系统按照CP设计。比如跨行转行,一次转账请求需要等待双方银行系统都完成,整个事务才算完成。需要说明:由于网络问题,该设计可能存在性能问题,导致出现超时等待的情况,如果没有及时处理超时问题,则可能导致整个系统出现阻塞情况。
AP:放弃强一致性,保证数据最终的一致性。加强可用性和分区容忍性,很多NOSQL数据库是按照AP设计的。
总结:在分布式系统中,AP的应用是比较多的,即保证系统的可用性和分区容忍性,牺牲数据的强一致性(写操作后立即读取新数据),保证数据的最终一致性。比如:订单退款、今日退款成功、明日到账等等。
两阶段提交由协调者和参与者组成,共经过两个阶段,三个操作,部分关系型数据库支持两阶段提交协议。
1)第一阶段:准备阶段,协调者通知参与者准备提交订单,参与者开始投票;参与者完成操作后向协调者返回操作结果YES|NO;
2)提交commit或回滚rollback阶段,协调者根据参与者返回的结果,想参与者发送提交或回滚的指令。
例如下单减库存(图是@村口张大爷的)
操作如下:
1)应用程序链接两个数据源;
2)应用事务协调器向两个库发起prepare,两个数据库分别执行本地事务(记录日志)但是不提交,如果执行结束则根据执行结果分别向协调器返回YES|NO。
3)协调器收到参与者返回的指令,只要其中一个参与者返回NO的指令,则向所有参与者发送回滚的执行,参与者回滚事务。
4)事务协调器收到YES指令,则向所有参与者发送提交指令,如果参与者有一方提交失败,则由事务协调器发起回滚事务。
2PC的优点,支持事务的强一致性,部分关系型数据库支持(MYSQL、SQLSERVER等)
缺点:整个事务需要协调者在多个参与者节点之间协调,执行时间长,性能低下。
实现方式:SpringBoot+Atomikos OR Bitronix
TCC事务补偿是基于2PC实现的业务层事务控制方案,Try\Confirm\Cancel
Try:检查并预留资源,完成事务执行前的检查,并预留事务执行所需要的资源;
Confirm:确定执行业务操作,对Try阶段预留的资源正式执行;
Cancel:确定取消业务操作,对Try阶段预留的资源执行释放;
例如下单减库存(图是@村口张大爷的)
操作如下:
Try:
1)下单业务由订单系统和库存系统协调完成,Try阶段对订单服务和库存服务进行检查,并预留事务执行所需的资源。
2)检查订单服务是否满足下单的条件(比如是否存在未提交的订单)。
3)检查库存服务是否满足下单的条件(比如库存是否充足)。
Confirm:
1)订单服务和库存服务在完成Try阶段后,正式开始执行业务操作。
2)订单服务向订单库中写入下单记录;
3)库存服务减去库存。
Cancel:
1)订单服务或是库存服务一方出现失败则全部取消操作。
2)订单服务需要删除新增的记录;
3)库存服务需要恢复库存。
TCC优点:最终保证数据的一致性,在业务层实现事务控制,灵活性好。
缺点:开发成本高,每个事务操作都需要参与者实现Try/Confirm/Cancel三个接口。
注意:Try/Confirm/Cancel三个接口都需要实现幂等性,在接口执行失败后不断重试。
幂等性,是指同一个操作无论执行多少次,返回的结果都是一致的。
实现方法:
1、操作之前在方法中进行判断,执行过了就不再重复执行了。
2、缓存所有请求和执行结果,已经处理的请求直接返回结果。
3、在数据表中加一个字段,数据操作时判断字段状态再处理。
消息队列实现将一个事务拆分成多个本地事务来完成,并且由消息队列异步协调完成。
例如下单件库存(图是@村口张大爷的)
执行过程:开始事务(AOP织入)-@Transaction修饰的方法-处理事务提交或回滚。
Transaction注解可以修饰方法也可以修饰类,修饰类的时候,默认对该类下符合条件的方法均织入事务。
1、开启事务:获取数据库连接,关闭自动提交。
2、异常回滚:默认情况下只有RuntimeException和Error会进行回滚的,因此回滚前会检查rollBackOn的关键字,查询注解是否做了显示的声明。
Required:支持当前事务,如果不存在,则新建一个事务执行。
Supports:支持当前事务,如果不存在,则以非事务方式执行。
Mandatory:强制的,支持当前事务,如果不存在,则抛出异常。
Required_New:不支持当前事务,创建一个新事务并挂起当前事务。
Not_Supports:以非事务方式执行,如果存在事务,则挂起,以非事务方式执行。
Never:以非事务方式执行,如果存在事务,则抛出异常。
Nested:如果存在当前事务,则嵌套事务执行,不存在则执行Required操作。