版本:
Springboot:2.2.0
SpringCloud: 2020.0.3
Seata: 1.4
1. 下载seata
1)地址:http://seata.io/zh-cn/blog/download.html
2)在conf文件夹修改file.conf文件
3)向本地数据库导入seata需要的表
- 创建名字为seata的数据库
- 新建表branch_table、global_table、lock_table
CREATE TABLE
branch_table
(
branch_id
bigint NOT NULL,
xid
varchar(128) NOT NULL,
transaction_id
bigint DEFAULT NULL,
resource_group_id
varchar(32) DEFAULT NULL,
resource_id
varchar(256) DEFAULT NULL,
lock_key
varchar(128) DEFAULT NULL,
branch_type
varchar(8) DEFAULT NULL,
status
tinyint DEFAULT NULL,
client_id
varchar(64) DEFAULT NULL,
application_data
varchar(2000) DEFAULT NULL,
gmt_create
datetime DEFAULT NULL,
gmt_modified
datetime DEFAULT NULL,
PRIMARY KEY (branch_id
),
KEYidx_xid
(xid
)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3;
CREATE TABLE
global_table
(
xid
varchar(128) NOT NULL,
transaction_id
bigint DEFAULT NULL,
status
tinyint NOT NULL,
application_id
varchar(32) DEFAULT NULL,
transaction_service_group
varchar(32) DEFAULT NULL,
transaction_name
varchar(128) DEFAULT NULL,
timeout
int DEFAULT NULL,
begin_time
bigint DEFAULT NULL,
application_data
varchar(2000) DEFAULT NULL,
gmt_create
datetime DEFAULT NULL,
gmt_modified
datetime DEFAULT NULL,
PRIMARY KEY (xid
),
KEYidx_gmt_modified_status
(gmt_modified
,status
),
KEYidx_transaction_id
(transaction_id
)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3;
CREATE TABLE
lock_table
(
row_key
varchar(128) NOT NULL,
xid
varchar(96) DEFAULT NULL,
transaction_id
mediumtext,
branch_id
mediumtext,
resource_id
varchar(256) DEFAULT NULL,
table_name
varchar(32) DEFAULT NULL,
pk
varchar(36) DEFAULT NULL,
gmt_create
datetime DEFAULT NULL,
gmt_modified
datetime DEFAULT NULL,
PRIMARY KEY (row_key
)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3;
4)修改registry.conf文件
5)将seata配置信息添加到nacos配置中心
1.启动本地的nacos服务
2.下载config.txt和nacos-config.sh两个文件
https://github.com/seata/seata/blob/develop/script/config-center/config.txt
https://github.com/seata/seata/blob/develop/script/config-center/nacos/nacos-config.sh
3.然后执行nacos-config.sh脚本
4.查看nacos中添加成功的配置
6)启动seata
进入bin目录下,执行
./seata-server.sh
出现下图即为启动成功
2. 服务间调用(服务one调用服务two)
1)创建one和two数据库,每个数据库都必须包含undo_log表
- one数据库
CREATE TABLE
count
(
id
int NOT NULL AUTO_INCREMENT,
count
int DEFAULT NULL COMMENT ‘库存’,
PRIMARY KEY (id
)
) ENGINE=InnoDB AUTO_INCREMENT=25 DEFAULT CHARSET=utf8mb3;
CREATE TABLE
undo_log
(
id
bigint NOT NULL AUTO_INCREMENT,
branch_id
bigint NOT NULL,
xid
varchar(100) NOT NULL,
context
varchar(128) NOT NULL,
rollback_info
longblob NOT NULL,
log_status
int NOT NULL,
log_created
datetime NOT NULL,
log_modified
datetime NOT NULL,
ext
varchar(100) DEFAULT NULL,
PRIMARY KEY (id
),
UNIQUE KEYux_undo_log
(xid
,branch_id
)
) ENGINE=InnoDB AUTO_INCREMENT=20 DEFAULT CHARSET=utf8mb3;
- two数据库
CREATE TABLE
order
(
id
int NOT NULL AUTO_INCREMENT,
order_count
int DEFAULT NULL,
product_id
bigint DEFAULT NULL,
PRIMARY KEY (id
)
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8mb3;
CREATE TABLE
undo_log
(
id
bigint NOT NULL AUTO_INCREMENT,
branch_id
bigint NOT NULL,
xid
varchar(100) NOT NULL,
context
varchar(128) NOT NULL,
rollback_info
longblob NOT NULL,
log_status
int NOT NULL,
log_created
datetime NOT NULL,
log_modified
datetime NOT NULL,
ext
varchar(100) DEFAULT NULL,
PRIMARY KEY (id
),
UNIQUE KEYux_undo_log
(xid
,branch_id
)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb3;
2) 创建one和two服务
此处省略创建服务过程。。。
maven父工程依赖
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<packaging>pom</packaging>
<modules>
<module>serviceone</module>
<module>servicetwo</module>
<!-- common是公共类-->
<module>servicecommon</module>
</modules>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.5.5</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>demo2</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>demo2</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
<spring-cloud.version>2020.0.3</spring-cloud.version>
<spring-cloud-alibaba.version>2021.1</spring-cloud-alibaba.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.9</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<version>2.3.3.RELEASE</version>
<scope>test</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/org.mybatis.spring.boot/mybatis-spring-boot-starter -->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.2.0</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-context</artifactId>
<version>2.2.3.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>2021.1</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.26</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-log4j -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-log4j</artifactId>
<version>1.3.8.RELEASE</version>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
</project>
- one服务:
bootstrap.yml文件
# Spring
spring:
application:
# 应用名称
name: service-one
profiles:
# 环境配置
active: dev
main:
allow-bean-definition-overriding: true
cloud:
nacos:
discovery:
# 服务注册地址
server-addr: localhost:8848
# namespace: 3d25ad9f-6b5a-4f1a-a4a7-0bbba90a00fa
group: SEATA_GROUP
config:
# 配置中心地址
server-addr: localhost:8848
namespace: 8221aa53-c648-4c6a-8a41-0c3a685ba58e
# # 配置文件格式
file-extension: yml
# # 共享配置
# shared-dataids: application-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension}
#
seata:
tx-service-group: my_test_tx_group
registry:
type: nacos
nacos:
server-addr: ${spring.cloud.nacos.discovery.server-addr}
group: ${spring.cloud.nacos.discovery.group}
# namespace: 6c990727-93b2-4081-a8c6-6b015c56eda2
config:
type: nacos
nacos:
server-addr: ${spring.cloud.nacos.discovery.server-addr}
group: ${spring.cloud.nacos.discovery.group}
# namespace: 6db428d4-e7a3-4dd3-be02-283960e0e704
service:
vgroup-mapping:
my_test_tx_group: default
nacos中one的配置(service-one-dev.yml):
# Spring
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/service-one?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
username: root
password: 123456789
server:
port: 8085
# Mybatis配置
mybatis:
# 配置mapper的扫描,找到所有的mapper.xml映射文件
mapperLocations: classpath:mapper/**/*.xml
# 我使用的这个版本这一步可以忽略
httpclient:
enabled: true
one服务依赖
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
</dependency>
<!--nacos-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<!-- https://mvnrepository.com/artifact/com.alibaba.cloud/spring-cloud-starter-alibaba-nacos-config -->
<!-- 不配置无法读取nacos配置 -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-loadbalancer</artifactId>
</dependency>
<!-- 升级spring cloud版本之后发现bootstrap.yml 失效了,阅读官方文档得知,需要新增一个引用来开启bootstrap.xml文件的读取,
新版spring cloud默认是关闭读取了。-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bootstrap</artifactId>
</dependency>
<!-- 不引入,bootstrap.yml无法使用 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-context</artifactId>
<version>3.0.2</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<!-- 添加feign -->
<!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-openfeign -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
<version>2.2.3.RELEASE</version>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.6.6</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.2.6</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-log4j</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-seata</artifactId>
</dependency>
<!-- 在 pom 中添加依賴,解决使用get方式请求时出现的Request method 'POST' not supported-->
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-httpclient</artifactId>
</dependency>
</dependencies>
controller :
@GetMapping("/insertOpt")
public CommonResult insertOpt() {
try {
countService.insertOpt();
return new CommonResult(true, "成功", null);
} catch (Exception e) {
return new CommonResult(false, "失败", null);
}
}
serviceImpl
@Override
@GlobalTransactional(rollbackFor = Exception.class, name = "insertOpt")
public CommonResult insertOpt() {
Count count = new Count();
count.setCount(12);
int insert = this.countDao.insert(count);
if (insert == 0) {
throw new RuntimeException("first失败");
}
Order order = new Order();
order.setOrderCount(12);
order.setProductId(12L);
CommonResult commonResult = remoteServiceTwo.insertOne(order);
if (!commonResult.getBool()){
throw new RuntimeException("操作远程失败!");
}
Map<String, Object> map = new HashMap<>(16);
map.put("count", insert);
map.put("order", commonResult);
System.err.println("map===="+ map.toString());
return new CommonResult(true, "成功", map);
}
feign请求
@FeignClient(value = "service-two")
public interface RemoteServiceTwo {
@PostMapping("/order/insertOne")
public CommonResult insertOne(Order order);
}
- two服务
bootstrap.yml
# Spring
spring:
application:
# 应用名称
name: service-two
profiles:
# 环境配置
active: dev
main:
allow-bean-definition-overriding: true
cloud:
nacos:
discovery:
# 服务注册地址
server-addr: localhost:8848
# namespace: 3d25ad9f-6b5a-4f1a-a4a7-0bbba90a00fa
group: SEATA_GROUP
config:
# 配置中心地址
server-addr: localhost:8848
namespace: 8221aa53-c648-4c6a-8a41-0c3a685ba58e
# # 配置文件格式
file-extension: yml
# # 共享配置
# shared-dataids: application-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension}
seata:
tx-service-group: my_test_tx_group
registry:
type: nacos
nacos:
server-addr: ${spring.cloud.nacos.discovery.server-addr}
group: ${spring.cloud.nacos.discovery.group}
# namespace: 6c990727-93b2-4081-a8c6-6b015c56eda2
config:
type: nacos
nacos:
server-addr: ${spring.cloud.nacos.discovery.server-addr}
group: ${spring.cloud.nacos.discovery.group}
service:
vgroup-mapping:
my_test_tx_group: default
pom.xml 依赖
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
</dependency>
<!--nacos-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<!-- https://mvnrepository.com/artifact/com.alibaba.cloud/spring-cloud-starter-alibaba-nacos-config -->
<!-- 不配置无法读取nacos配置 -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-loadbalancer</artifactId>
</dependency>
<!-- 升级spring cloud版本之后发现bootstrap.yml 失效了,阅读官方文档得知,需要新增一个引用来开启bootstrap.xml文件的读取,
新版spring cloud默认是关闭读取了。-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bootstrap</artifactId>
</dependency>
<!-- 不引入,bootstrap.yml无法使用 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-context</artifactId>
<version>3.0.2</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<!-- 添加feign -->
<!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-openfeign -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
<version>2.2.3.RELEASE</version>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.6.6</version>
</dependency>
<dependency>
<groupId>com.example</groupId>
<artifactId>servicecommon</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.2.6</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-log4j -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-log4j</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-seata</artifactId>
</dependency>
</dependencies>
nacos中two服务的配置service-two-dev.yml
# Spring
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/service-two?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
username: root
password: 123456789
server:
port: 8086
# Mybatis配置
mybatis:
# 配置mapper的扫描,找到所有的mapper.xml映射文件
mapperLocations: classpath:mapper/**/*.xml
# 我使用的这个版本这一步可以忽略
httpclient:
enabled: true
two服务controller
@PostMapping("insertOne")
public CommonResult selectOne(@RequestBody Order order) {
try {
this.orderService.insert(order);
return new CommonResult(true, "成功", null);
} catch (Exception e) {
StaticLog.error("失败:======{}", e);
return new CommonResult(false, "失败", null);
}
}
serviceImpl
/**
* 新增数据
*
* @param order 实例对象
* @return 实例对象
*/
@Override
public Order insert(Order order) {
// int a = 1/0; // 此处是为了出现错误,看seata是否会回滚
this.orderDao.insert(order);
return order;
}
3. 查看结果
- 插入成功操作
浏览器操作
serviceone的日志
servicetwo日志
数据库结果-插入成功 (清空数据库进行插入失败操作)
- 插入失败操作
1) 插入失败,进行回滚—在servicetwo业务代码上添加一个报错代码
浏览器操作
serviceone 日志(进行了回滚)
servicetwo 日志
数据库数据