gitee:https://gitee.com/JiaBin1
一、什么是分布式事务
在我们传统的单体的项目使用的事务都是本地事务
,事务管理是1:1
管理方式
而当我们的传统的单体项目被拆分成多个微服务应用,就比如三个模块 用户、商品、订单模块被拆分为三个独立的微服务应用,整体业务需要调用上述三个模块才能完成。此时每个服务内部的数据一致性由本地事务来保证, 但是全局的数据一致性问题没法保证
想象一下,当我们扣除账户余额的时候若出现了网络波动或者程序异常,此时我们已经的商品库存已经扣除了,这样就造成了事务的一致性问题
一句话:一次业务操作需要跨多个数据源或需要跨多个系统进行远程调用,就会产生分布式事务问题。
二、Seata解决方案
1、什么是Seata
Seata是SpringCloud Alibaba的一个开源的分布式解决方案,Seata是一个二阶段
提交事务协议,Seata总共提供1+3组件:
- XID:全局唯一事务ID -------- 班级号
- TC:事务协调者 -------- 教员
- TM:事务管理器 -------- 班主任
- RM:资源管理器 -------- 学生
执行流程
【官方的】
【自己理解的】
2、配置Seata
注意:这里我们使用的seata的版本为0.9
-
打开conf目录下的file.conf文件
【1、指定数据源名称】
【2、修改存储模式为db】
【3、修改数据库连接配置】
-
创建数据库 seata
【1、创建数据库 seata】
-
create database seata; use seata;
【2、复制建表语句 seata>conf>db_store.sql文件】
【3、建表完成后的内容】
-
-
修改注册文件 registry.conf
【1、修改注册中心配置】
-
-
启动nacos
-
启动seata
3、使用Seata
-
在我们需要管理事务的数据库中添加表
【该表在 seata > conf > db_undo_log.sql 文件】
-
-- the table to store seata xid data -- 0.7.0+ add context -- you must to init this sql for you business databese. the seata server not need it. -- 此脚本必须初始化在你当前的业务数据库中,用于AT 模式XID记录。与server端无关(注:业务数据库) -- 注意此处0.3.0+ 增加唯一索引 ux_undo_log drop table `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;
-
-
导入seata依赖
【注意:seata版本要与启动的一致】
-
<!--seata--> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-seata</artifactId> <exclusions> <exclusion> <artifactId>seata-all</artifactId> <groupId>io.seata</groupId> </exclusion> </exclusions> </dependency> <dependency> <groupId>io.seata</groupId> <artifactId>seata-all</artifactId> <version>0.9.0</version> </dependency>
-
-
在我们
每个
需要事务管理的微服务资源目录下添加文件【其文件内容见
gitee:https://gitee.com/JiaBin1
目录下】 -
项目配置文件
【application.yaml】
-
server: port: 8663 spring: application: name: ORDER-SERVER cloud: alibaba: seata: # 配置seata tx-service-group: abt_tx_group # 指定分组名称 nacos: discovery: server-addr: localhost:8848 datasource: driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://127.0.0.1:3306/shopping_db username: root password: root feign: hystrix: enabled: false logging: level: io: seata: info mybatis-plus: type-aliases-package: com.jiabin.pojo mapper-locations: classpath:mapper/*.xml
-
-
在启动类中取消数据源的自动创建,使用我们自己定义的
-
/** * @Author 嘉宾 * @Data 2022/6/30 21:39 * @Version 1.0 * @Description */ @EnableFeignClients // 开启openFeign @SpringBootApplication(exclude = DataSourceAutoConfiguration.class) // 取消数据源的自动创建,而是使用自己定义的 public class OrderServerApplication { public static void main(String[] args) { SpringApplication.run(OrderServerApplication.class,args); } }
【DataSourceProxyConfig】自定义数据源
-
/** * @Author 嘉宾 * @Date 2021/10/31 16:41 * @Description: */ @Configuration public class DataSourceProxyConfig { //@Value("${mybatis-plus.mapper-locations}") private String mapperLocations = "classpath:mapper/*.xml"; @Bean @ConfigurationProperties(prefix = "spring.datasource") public DataSource druidDataSource(){ return new DruidDataSource(); } @Bean public DataSourceProxy dataSourceProxy(DataSource dataSource) { return new DataSourceProxy(dataSource); } @Bean public MybatisSqlSessionFactoryBean sqlSessionFactoryBean(DataSourceProxy dataSourceProxy) throws Exception { MybatisSqlSessionFactoryBean sqlSessionFactoryBean = new MybatisSqlSessionFactoryBean(); sqlSessionFactoryBean.setDataSource(dataSourceProxy); sqlSessionFactoryBean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources(mapperLocations)); sqlSessionFactoryBean.setTransactionFactory(new SpringManagedTransactionFactory()); return sqlSessionFactoryBean; } }
-
-
在我们需要事务管理的方法上添加注解
-
@GlobalTransactional(name = "事务名称(随便给)",rollbackFor = Exception.class) // 开启分布式事务
-
-
至此使用seata解决事务管理完成