17-Ali-Seata
本笔记来源于:尚硅谷SpringCloud框架开发教程(SpringCloudAlibaba微服务分布式架构丨Spring Cloud)
b站视频
文章来自:
https://github.com/OT-mt/cloud2020/tree/master/springcloud-2%E5%B0%9A%E7%A1%85%E8%B0%B7%E5%91%A8%E9%98%B3-2020
脑图
简介
解决问题
- 分布式前Java服务与数据库1->1
- 分布式后 1->1,1>多,多->多
保证多个服务之间的数据一致性是什么
Seata 是一款开源的分布式事务解决方案,致力于提供高性能和简单易用的分布式事务服务。Seata 将为用户提供了 AT、TCC、SAGA 和 XA 事务模式,为用户打造一站式的分布式解决方案。官网
http://seata.io/zh-cn/处理过程
一ID+三组件
- id
全局唯一的事务ID - 3组件
- TM向TC申请开启一个全局事务,全局事务创建成功并生成一个全局唯一的XID
- XID在微服务调用链路的上下文中传播
- RM向TC注册分支事务,将其纳入XID对应全局事务的管辖
- TM 向 TC 发起针对 XID 的全局提交或回滚请求
- TC 调度 XID 下管辖的全部分支事务完成提交或回滚请求
安装
找到conf下的 file.conf
将 mode 改为 db代表将日志存储到数据库
修改数据库账号密码端口
找到 register.conf
将 registry 与 config 里的 type均改为nacos
同时修改两者下面的 nacos信息创建数据库 seata
数据库加载文件
查看RANDME.MD server 对应网址即可
实验
数据库
- 创建数据库
- create database seata_order;订单
- create database seata_storage;库存
- create database seata_account;账户信息
- 建表
- seata_order下建t_order
- seata_storage下建 t_storage;
- seata_account下建 t_account
- 建表sql
1
2
3
4
5
6
7
8create table t_order(
id bigint(11) not null auto_increment primary key,
user_id bigint(11) default null comment '用户id',
product_id bigint(11) default null comment '产品id',
count int(11) default null comment '数量',
money decimal(11,0) default null comment '余额',
status int(1) default null comment '订单状态'
)建模块
seata-order-service2001
- pom
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21<!-- seata -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-seata</artifactId>
<exclusions>
<exclusion>
<groupId>io.seata</groupId>
<artifactId>seata-all</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- 引入与自己版本相同的 -->
<dependency>
<groupId>io.seata</groupId>
<artifactId>seata-all</artifactId>
<version>1.2.0</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
##########################
依赖
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-seata</artifactId>
<exclusions>
<exclusion>
<groupId>io.seata</groupId>
<artifactId>seata-spring-boot-starter</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- 引入与自己版本相同的 -->
<dependency>
<groupId>io.seata</groupId>
<artifactId>seata-spring-boot-starter</artifactId>
<version>1.2.0</version>
</dependency>yml
config.txt nacos-config.sh 上传配置
本例使用seata1.2
创建seata数据库
- 找到 seata/conf 下的 README-zh.md
- 进入 server
- 找到 db 下的 mysql.sql
- 创建数据库 seata ,后执行mysql.sql
- mysql.sql中的三张表为 seata配置必须的表
创建业务必须数据库
用以做案例1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26-- 建数据库,订单
create database seata_order;
use seata_order;
-- 建订单表
CREATE TABLE `t_order` (
`id` INT(11) NOT NULL AUTO_INCREMENT,
`name` VARCHAR(50) NULL DEFAULT NULL,
PRIMARY KEY (`id`)
)
COLLATE='utf8_general_ci'
ENGINE=InnoDB
AUTO_INCREMENT=8
;
-- 建数据库,库存
create database seata_storage;
-- 建库存表
CREATE TABLE `t_storage` (
`id` INT(11) NOT NULL,
`num` INT(11) NOT NULL,
PRIMARY KEY (`id`)
)
COLLATE='utf8_general_ci'
ENGINE=InnoDB
;
-- 初始化库存数量
insert into t_storage values(1,20);
- 找到 seata/conf 下的 README-zh.md
- 进入 client
- 找到db下的mysql.sqlclient
- 其中为一建表sql
- ==每一个分布式业务数据库都需要这张表,即在新建的数据库 seata_order 与 seata_storage中新建该表==
修改seata1.2
- 找到 seata/conf/file.conf
将 store 下的 mode 改为 db ,代表采用数据库配置
更改 store下数据库的相关配置 - 找到 seata/conf/registry.conf
将 type 改为 nacos 同时修改 nacos中的信息和config下nacos的信息1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27registry {
# file 、nacos 、eureka、redis、zk、consul、etcd3、sofa
type = "nacos"
nacos {
application = "seata-server"
serverAddr = "localhost:8848"
namespace = ""
cluster = "default"
username = "nacos"
password = "nacos"
}
}
config {
# file、nacos 、apollo、zk、consul、etcd3
type = "nacos"
nacos {
serverAddr = "localhost:8848"
namespace = ""
group = "SEATA_GROUP"
username = "nacos"
password = "nacos"
}
}为nacos添加配置信息
- 访问 config-center
- 将 config.txt 拷贝到 seata/下
- 修改config.txt内容为下列,因为其余配置为默认或无用配置
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15service.vgroupMapping.my_test_tx_group=default
store.mode=db
store.db.datasource=druid
store.db.dbType=mysql
store.db.driverClassName=com.mysql.jdbc.Driver
store.db.url=jdbc:mysql://127.0.0.1:3306/seata?useUnicode=true
store.db.user=root
store.db.password=root
store.db.minConn=5
store.db.maxConn=30
store.db.globalTable=global_table
store.db.branchTable=branch_table
store.db.queryLimit=100
store.db.lockTable=lock_table
store.db.maxWait=5000 - 将 nacos 下的 nacos-config.sh 拷贝到 seata/conf/ 下
- 启动nacos
- 使用 Git Bash Here 切换到 seata/conf/ 下执行命令
sh nacos-config.sh
- 查看nacos中是否有 seata 相关的配置信息。
配置业务seata-order-service2001
- pom
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73<dependencies>
<!--引入自己的公共api-->
<dependency>
<groupId>com.wxh.springcloud</groupId>
<artifactId>cloud-api-commons</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<!--热部署-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<!-- 使用openfeign做微服务调用 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-seata</artifactId>
<exclusions>
<exclusion>
<groupId>io.seata</groupId>
<artifactId>seata-spring-boot-starter</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- 引入与自己版本相同的 -->
<dependency>
<groupId>io.seata</groupId>
<artifactId>seata-spring-boot-starter</artifactId>
<version>1.2.0</version>
</dependency>
</dependencies> - yml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50# 端口号
server:
port: 2001
spring:
application:
name: seata-order-service
cloud:
nacos:
discovery: #Nacos注册中心地址
server-addr: localhost:8848
datasource:
type: com.alibaba.druid.pool.DruidDataSource #数据源类型
driver-class-name: org.gjt.mm.mysql.Driver #mysql驱动包
url: jdbc:mysql://localhost:3306/seata_order?useUnicode=true&characterEncoding=utf-8&useSSL=false
username: root
password: root
feign:
hystrix:
enabled: true
logging:
level:
io:
seata: info
mybatis:
mapper-locations: classpath:mapper/*.xml
seata:
enabled: true
# 应用 id 为唯一便于区分
application-id: order
# 事务分组,这个是默认分组
tx-service-group: my_test_tx_group
config:
type: nacos
nacos:
namespace:
serverAddr: 127.0.0.1:8848
group: SEATA_GROUP
userName: "nacos"
password: "nacos"
registry:
type: nacos
nacos:
application: seata-server
server-addr: 127.0.0.1:8848
namespace:
userName: "nacos"
password: "nacos" - mapper
1
2
3
4
5
6@Mapper
public interface OrderMapper {
// 插入一条订单
@Insert("insert into t_order values(null,'test')")
public void test();
} - service:接口类省略
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16@Service
public class OrderServiceImpl implements OrderService {
@Resource
OrderMapper orderMapper;
@Resource
StroageService stroageService;
@Override
// name对应配置文件里的事务分组
@GlobalTransactional(name = "my_test_tx_group",rollbackFor = Exception.class)
public void test() {
orderMapper.test();
stroageService.test();
}
} - StorageService.java
1
2
3
4
5@FeignClient(value = "seata-storage-service")
public interface StroageService {
@RequestMapping("/test")
public String test();
} - controller
1
2
3
4
5
6
7@Resource
private OrderService orderService;
@RequestMapping("/test")
public String test(){
orderService.test();
return "test";
}配置业务模块seata-storage-service2003
- pom 与上一模块相同
- yml 与上一模块相同
- 更改端口号
- 更改spring.application.name.
- 更改seata.application-id: storage
- 为了方便省去service由controller直接调用mapper
- mapper
1
2
3
4
5
6@Mapper
public interface StorageMapper {
// 代表库存减1
@Update("UPDATE t_storage SET num = num-1 WHERE id = 1")
public void test();
} - controller
1
2
3
4
5
6
7
8
9
10
11
12
13
14@RestController
public class StorageController {
@Resource
StorageMapper storageMapper;
@RequestMapping("/test")
public String test(){
// int a = 1/0; // 模拟异常
storageMapper.test();
return "storage";
}
}测试
- 正常启动两个模块
- 访问http://localhost:2001/test查看是否能成功访问
- 启动模拟异常
- 将模块 seata-order-service2001 中 OrderServiceImpl.class 下的 stroageService.test();打上断点
- debug 启动seata-order-service2001
- 访问 http://localhost:2001/test
- 此时进入断点
- 查看 t_order 表中新增一条数据,数据库中 seata_order 下的 undo_log 表中增加信息,代表事务
- 数据库 seata_order 的 undo_log 表中添加事务信息
- 结束执行代码
- t_order 表中数据消失
- 数据库 seata_order 的 undo_log 表数据消失
- 测试成功
修改事务分组
- yml中
seata:
tx-service-group: test - nacos中新增配置
service.vgroupMapping.test
内容为 default - service.vgroupMapping.test 的值为集群名称,test即事务分组 ,default代表无集群
17-Ali-Seata
http://yuanql.top/2023/06/27/13_SpringCloud/springcloud-2尚硅谷周阳-2020/17-Ali-Seata/