一、本地事务
1.1 事务的基本性质:
原子性(Atomicity )、一致性( Consistency )、隔离性或独立性( Isolation)、持久性(Durabilily),简称就是 ACID
1) 原子性:一系列的操作整体不可拆分,要么同时成功,要么同时失败
2) 一致性:数据在事务的前后,业务整体一致。
eg: 转账。A:1000;B:1000; 转 200 事务成功; A:800 B:1200
3) 隔离性:事务之间互相隔离。
4) 持久性:一旦事务成功,数据一定会落盘在数据库。
1.2 事务的隔离级别:
1) READ UNCOMMITTED(读未提交) 该隔离级别的事务会读到其它未提交事务的数据,此现象也称之为脏读。
2) READ COMMITTED(读提交) 一个事务可以读取另一个已提交的事务,多次读取会造成不一样的结果,此现象称为不可重 复读问题,Oracle 和 SQL Server 的默认隔离级别。
3) REPEATABLE READ(可重复读) 该隔离级别是 MySQL 默认的隔离级别,在同一个事务里,select 的结果是事务开始时时间 点的状态,因此,同样的 select 操作读到的结果会是一致的,但是,会有幻读现象。MySQL 的 InnoDB 引擎可以通过 next-key locks 机制(参考下文"行锁的算法"一节)来避免幻读。
4) SERIALIZABLE(序列化) 在该隔离级别下事务都是串行顺序执行的,MySQL数据库的 InnoDB 引擎会给读操作隐式 加一把读共享锁,从而避免了脏读、不可重读复读和幻读问题。
可通过@Transactional(isolation = Isolation.REPEATABLE_READ) 进行设置。
1.3 事务的隔离级别:
1、PROPAGATION_REQUIRED:如果当前没有事务,就创建一个新事务,如果当前存在事务, 就加入该事务,该设置是最常用的设置。
2、PROPAGATION_SUPPORTS:支持当前事务,如果当前存在事务,就加入该事务,如果当 前不存在事务,就以非事务执行。
3、PROPAGATION_MANDATORY:支持当前事务,如果当前存在事务,就加入该事务,如果 当前不存在事务,就抛出异常。
4、PROPAGATION_REQUIRES_NEW:创建新事务,无论当前存不存在事务,都创建新事务。 5、PROPAGATION_NOT_SUPPORTED:以非事务方式执行操作,如果当前存在事务,就把当 前事务挂起。
6、PROPAGATION_NEVER:以非事务方式执行,如果当前存在事务,则抛出异常。
7、PROPAGATION_NESTED:如果当前存在事务,则在嵌套事务内执行。如果当前没有事务, 则执行与 PROPAGATION_REQUIRED 类似的操作。
【举个栗子】
非springboot的本地事务
1.4 SpringBoot 事务:
1).事务的自动配置
TransactionAutoConfiguration
2).事务的坑。。。。坑:
快快快。。。知识点
现象:在同一个类里面,编写两个方法,内部调用的时候,会导致事务设置失效。
原因:事务是使用代理对象来控制的。同一对象内,事务方法互调,默认失效;原因绕过了代理对象
解决:
0)、导入 spring-boot-starter-aop
1)、@EnableTransactionManagement(proxyTargetClass = true)
2)、@EnableAspectJAutoProxy(exposeProxy=true)
3)、AopContext.currentProxy() 调用方法
二、分布式事务
1).CAP 定理
CAP 原则又称 CAP 定理,指的是在一个分布式系统中
1) 一致性(Consistency): 在分布式系统中的所有数据备份,在同一时刻是否同样的值。(等同于所有节点访问同一份最新的数据副本)
2) 可用性(Availability) 在集群中一部分节点故障后,集群整体是否还能响应客户端的读写请求。(对数据更新具备高可用性)
3) 分区容错性(Partition tolerance) 大多数分布式系统都分布在多个子网络。每个子网络就叫做一个区(partition)。 分区容错的意思是,区间通信可能失败。比如,一台服务器放在中国,另一台服务器放在美国,这就是两个区,它们之间可能无法通信。
CAP 原则指的是,这三个要素最多只能同时实现两点,不可能三者兼顾。 一般来说,分区容错是无法避免的,因此可以认为CAP的p 总是成立的,那么CAP定理告诉我们,剩下的C、A是无法同时满足的
2).面对现实吧
对于多数大型互联网应用的场景,主机众多、部署分散,而且现在的集群规模越来越大,所 以节点故障、网络故障是常态,而且要保证服务可用性达到 99.99999%(N 个 9),即保证 P 和 A,舍弃 C。
是对 CAP 理论的延伸,思想是即使无法做到强一致性(CAP 的一致性就是强一致性),但可 以采用适当的采取弱一致性,即最终一致性。
BASE 理论:
1)基本可用(Basically Available)2)软状态( Soft State)3) 最终一致性( Eventual Consistency)
3)分布式事务几种方案:
1).2PC 模式、3PC:
2).柔性事务-TCC 事务补偿型方案
3).柔性事务-最大努力通知型方案
4).柔性事务-可靠消息 + 最终一致性方案(异步确保型)
实现:业务处理服务在业务事务提交之前,向实时消息服务请求发送消息,实时消息服务只 记录消息数据,而不是真正的发送。业务处理服务在业务事务提交之后,向实时消息服务确 认发送。只有在得到确认发送指令后,实时消息服务才会真正发送。
防止消息丢失:
1、做好消息确认机制(pulisher,consumer【手动 ack】)
2、每一个发送的消息都在数据库做好记录。定期将失败的消息再次发送一 遍
4)Raft原理:
分布式系统中实现一致性的 raft 算法、paxos
节点状态:候选人、领导、随从
关键词: 自旋、心跳、选举
5)Seata
Seata 是一款开源的分布式事务解决方案,致力于提供高性能和简单易用的分布式事务服务。Seata 将为用户提供了 AT、TCC、SAGA 和 XA 事务模式,为用户打造一站式的分布式解决方案。
5.1 SEATA 的分布式交易解决方案
5.2 使用
* Seata控制分布式事务
* 1)、每一个微服务先必须创建undo_logo;
* 2)、安装事务协调器;seata-server: https://github.com/seata/seata/releases
* 3)、整合
* 1、导入依赖 spring-cloud-starter-alibaba-seata seata-all-1.0.0.jar
* 2、解压并启动seata-server
* registry.conf注册中心相关的配置,修改registry type=nacos
* file.conf
* 3、所有想要用到分布式事务的微服务使用seata DatasourceProxy代理自己的数据源
* 4、每个微服务,都必须导入registry.conf、file.conf 到resources下
* 修改order、ware的file.conf
* vgroup_mapping.{application.name}-fescar-service-group = "default"
如:
vgroup_mapping.gulimall-order-fescar-service-group = “default”
vgroup_mapping.gulimall-ware-fescar-service-group = “default”
或者 配置文件配置
#spring.cloud.alibaba.seata.tx-service-group=sss
* 5、启动测试
* 6、给分布式大事务的路口标注@GlobalTransactional
* 7、每一个远程的小事务用 @Transactional
1).创建 UNDO_LOG 表 -每个数据库都加
SEATA AT 模式需要 UNDO_LOG 表
– 注意此处0.3.0+ 增加唯一索引 ux_undo_log
CREATE TABLE undo_log (
id bigint(20) NOT NULL AUTO_INCREMENT,
branch_id bigint(20) NOT NULL,
xid varchar(100) NOT NULL,
context varchar(128) NOT NULL,
rollback_info longblob NOT NULL,
log_status int(11) NOT NULL,
log_created datetime NOT NULL,
log_modified datetime NOT NULL,
ext varchar(100) DEFAULT NULL,
PRIMARY KEY (id),
UNIQUE KEY ux_undo_log (xid,branch_id)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
5.3 seata弊端
高并发下,分布式事务不适合seata,@GlobalTransactional
高并发下,可使用:可靠消息 + 最终一致性方案(异步确保型)
为了保证高并发,远程服务自己回滚。
1、可以发消息给远程服务
2、远程服务自己也可以回滚(自动解锁模式),消息(延迟队列)
添加seata配置类 --把Seata作为数据库代理
例如order项目:
order中
@Configuration
public class MySeataConfig {
@Autowired
DataSourceProperties dataSourceProperties;
@Bean
public DataSource dataSource(DataSourceProperties dataSourceProperties) {
HikariDataSource dataSource = dataSourceProperties.initializeDataSourceBuilder().type(HikariDataSource.class).build();
if (StringUtils.hasText(dataSourceProperties.getName())) {
dataSource.setPoolName(dataSourceProperties.getName());
}
return new DataSourceProxy(dataSource);
}
}