一.本地事物
1.事物的基本性质
数据库事物的几个特性:原子性、一致性、隔离性或者独立性和持久性。简称就是ACID.
-
原子性:一系列的操作整体不可拆分,要么同时成功,要么同时失败
-
一致性:数据在事物的前后,业务整体一致。
转账. A:1000;B.1000; 转200 事物成功 A:800 B:1200
-
隔离性:事物之间相互隔离
-
持久性:一旦事物成功,数据一定会洛盘在数据库
在以往的单体应用中,我们多个业务操作使用同一条连接操作不同的数据表,一旦有异常,我们可以很容易的整体回滚
Business:我们具体业务代码
Storage:库存业务代码;扣库存
Order:订单业务代码;保存订单
Account:账号业务代码,减账户余额
比如买东西业务,扣库存,下订单,账户扣款,是一个整体;必须同时成功或者失败
一个事物开始,代码一下的所有操作都在一个连接里面;
2.事物的隔离级别
-
READ-UNCOMMITTED(读取未提交):最低的隔离级别,允许读取尚未提交的数据变更,可能会导致脏读、幻读或不可重复读。
-
READ-COMMITTED(读取已提交): 允许读取并发事务已经提交的数据,可以阻止脏读, 但是幻读或不可重复读仍有可能发生。 mysql和oracl默认隔离级别
-
REPEATABLE-READ(可重复读):对同一字段的多次读取结果都是一致的,除非数据是被 本身事务自己所修改,可以阻止脏读和不可重复读,但幻读仍有可能发生。
-
SERIALIZABLE(可串行化): 最高的隔离级别,完全服从ACID的隔离级别。所有的事务依次 逐个执行,这样事务之间就完全不可能产生干扰,也就是说,该级别可以防止脏读、不可重 复读以及幻读
3.事物的传播行为
1、PROPAGATION_REQUIRED:如果当前没有事务,就创建一个新事务,如果当前存在事务,就加入该事务,该设置是最常用的设置。
2、PROPAGATION_NESTED:如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则执行与PROPAGATION_REQUIRED类似的操作
3、PROPAGATION_SUPPORTS:支持当前事务,如果当前存在事务,就加入该事务,如果当前不存在事务,就以非事务执行。‘
4、PROPAGATION_MANDATORY:支持当前事务,如果当前存在事务,就加入该事务,如果当前不存在事务,就抛出异常。
5、PROPAGATION_REQUIRES_NEW:支持当前事务,创建新事务,无论当前存不存在事务,都创建新事务。
6、PROPAGATION_NOT_SUPPORTED:以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
7、PROPAGATION_NEVER:以非事务方式执行,如果当前存在事务,则抛出异常
4.springboot事物关键点
1.事物的自动配置
TransactionManagement
2.事物的坑
在同一个类里面,编写两个方法,内部调用的时候,会导致事物设置失效,原因是没有用到代理对象的缘故
//同一个对象内事物方法互调问题失效,原因:饶过了代理对象
//事物是代理对象来控制的
@Transactional(timeout = 30)//a事物的所有设置都会传播到和他公用一个事物的方法
public void a() {
//b,c做任何设置都是没用,都和a公用一个事物
//orderService.b();
//orderService.c();
OrderServiceImpl orderService = (OrderServiceImpl) AopContext.currentProxy();
orderService.b();
orderService.c();
//bservice.b();//a事物
//cservice.c();//新事物(不回滚)
int i = 10 / 0;
}
@Transactional(propagation = Propagation.REQUIRED)
public void b() {
}
@Transactional(propagation = Propagation.REQUIRES_NEW, timeout = 20)
public void c() {
}
解决:
本地事物失效问题
同一个对象内事物方法互调问题失效,原因:饶过了代理对象,事物是代理对象来控制的
解决方案:使用代理对象来调用事物的方法
1.引用aop-starter spring-boot-starter-aop引入了aspectj
2.@EnableAspectJAutoProxy,开启aspectj动态代理功能.所有的动态代理都是aspectj创建的(即使没有接口也可以创建动态代理)
exposeProxy = true对外暴露代理对象
3.用代理对象的类互调
OrderServiceImpl orderService = (OrderServiceImpl) AopContext.currentProxy();
orderService.b();
orderService.c();
二.分布式事物
1.为什么会有分布式事物
分布式系统经常出现的异常
机器宕机,网络异常,消息丢失,消息乱序,数据错误,不可靠的TCP,存储数据丢失…
分布式事物是企业集成中的一个技术难点,也是每一个分布式系统架构中都会涉及到的一个东西,特别是在微服务架构中,几乎可以说无法避免。
2.CAP定理与分布式事务
1.CAP定理
CAP原则又称CAP定理,指的是在一个分布式系统中
- 一致性:在分布式系统中的所有数据备份,在同一时刻是否同样的值(等同于所有节点访问同一份最新的数据副本)
- 可用性:在集群中一部分节点故障后,集群整体是否 能响应客户端的读写请求(对应更新具备高可用性)
- 分区容错性:大多数分布式系统分布在多个子网络。每个子网络叫一个区。分区容错的意思是。区间通行可能失败。比如。一台服务器放在中国。另一台服务器放在美国。这就是两个区。他们之间可能无法通行
CAP原则指的是。这三个要素最多只能同时实现两点。不可能三者兼顾。
一般来说,分区容错无法避免,因此可以认为CAP和p总是成立,CAP定理告诉我们,剩下C和A无法同时做到
分布式系统中实现一致性的raft算法
2.面临的问题
对于大多数互联网应用的场景,主机众多。部署分散,而且现在的集群规模越来越大,所以节点故障。网络故障是常态,而且要保证服务可用达到99.9999%,即保证P和A,舍弃C
3.BASE理论
是对于CAP理论的延申,思想是即使无法做到强一致性(CAP的一致性就是强一致性),但可用采用适当的采取弱一致性,即最终一致性。
BASE是指:
-
基本可用性 什么是基本可用呢?假设系统,出现了不可预知的故障,但还是能用,相比较正常的系统而言:
1.响应时间上的损失:正常情况下的搜索引擎0.5秒即返回给用户结果,而基本可用的搜索引擎可以在2秒作用返回结果。
2.功能上的损失:在一个电商网站上,正常情况下,用户可以顺利完成每一笔订单。但是到了大促期间,为了保护购物系统的稳定性,部分消费者可能会被引导到一个降级页面。
-
软状态 什么是软状态呢?相对于原子性而言,要求多个节点的数据副本都是一致的,这是一种“硬状态”。
软状态指的是:允许系统中的数据存在中间状态,并认为该状态不影响系统的整体可用性,即允许系统在多个不同节点的数据副本存在数据延时。
-
最终一致性 上面说软状态,然后不可能一直是软状态,必须有个时间期限。在期限过后,应当保证所有副本保持数据一致性,从而达到数据的最终一致性。这个时间期限取决于网络延时、系统负载、数据复制方案设计等等因素
4.强一致性,弱一致性,最终一致性
从客户端角度,多进程并发访问时,更新的数据在不同进程如何获取的不同策略,决定了不同的一致性。对于关系型数据库,要求更新过的数据能被后续访问都能看到。这就是强一致性。如果能容忍后续的部分或者全部访问不到,则是弱一致性。如果经过一段时间后要求能访问到更新后的数据。则是最终一致性。
3.分布式事物的几种方案
1.柔性事物-TCC事物补偿性方案
刚性事物:遵循ACID原则。强一致性。
柔性事物:遵循BASE理论。最终一致性
与刚性事物不同,柔性事物允许一定时间内,不同节点的数据不一致。但要求最终一致。
一阶段prepare行为:调用自定义的prepare逻辑。
二阶段commit行为:调用自定义的commit逻辑。
一阶段rollback行为:调用自定义的rollback逻辑。
所谓TCC模式。是指支持把自定义的分支事物纳入到全局事物的管理中。
2.柔性事物-最大努力通知型方案
按照规律进行通知,**不保证数据一定能通知成功,但会提供可查询操作接口进行核对。**这种方案主要用在第三方系统通讯时。比如:调用微信或者支付宝后的支付通知。这种方案也是结合MQ进行实现。比如:通过MQ发送http请求,设置最大通知次数,达到通知次数后即不在通知。
3.柔性事物-可靠消息+最总一致性方案(异步确保型)
实现:业务处理服务器在业务事物提交之前。向实时消息服务器请求消息,实时消息服务只记录消息数据,而不是真正的发送。业务处理服务在业务事物提交之后,向实时消息服务确认发送。只有在得到确认后发送指令后,实时消息服务菜会真正发送