文章目录
- 🔥Seata提供XA模式实现分布式事务_业务说明
- 🔥Seata提供XA模式实现分布式事务_下载启动Seata服务
- 🔥Seata提供XA模式实现分布式事务_搭建聚合父工程构建
- 🔥Seata提供XA模式实现分布式事务_转账功能实现上
- 🔥Seata提供XA模式实现分布式事务_转账功能实现下
🔥Seata提供XA模式实现分布式事务_业务说明
业务说明
本实例通过Seata中间件实现分布式事务,模拟两个账户的转账交易
过程。两个账户在两个不同的银行(张三在bank1、李四在bank2),bank1和bank2是两个微服务。交易过程中,张三给李四转账制定金额。上述交易步骤,要么一起成功,要么一起失败,必须是一个整体性的事务。
工程环境
服务名称 | 服务版本 |
---|---|
数据库 | MySQL-5.7.25 |
JDK | 1.8 |
微服务框架 | Spring-boot-2.6.3、Spring-Cloud-2021.0.0、Spring-Cloud-Alibaba-2021.0.1.0 |
Seata客户端(RM、TM) | Spring-cloud-alibaba-seata-2021.0.1.0 |
Seata服务端(TC) | Seata-server-1.4.2 |
服务注册 | Nacos |
Mybatis plus | 3.5.1 |
创建数据库
bank1库,包含张三账户
CREATE DATABASE /*!32312 IF NOT EXISTS*/bank1;
/*!40100 DEFAULT CHARACTER SET utf8 */;
USE bank1;
/*Table structure for table account_info */
DROP TABLE IF EXISTS account_info;
CREATE TABLE account_info (id bigint(20) NOT NULL AUTO_INCREMENT,
account_name varchar(100) COLLATE utf8_bin DEFAULT NULL COMMENT '户主姓名',
account_no varchar(100) COLLATE utf8_bin DEFAULT NULL COMMENT '银行卡号',
account_password varchar(100) COLLATE utf8_bin DEFAULT NULL COMMENT '帐户密码',account_balance double DEFAULT NULL COMMENT '帐户余额',
PRIMARY KEY (id) USING BTREE) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULTCHARSET=utf8 COLLATE=utf8_bin
ROW_FORMAT=DYNAMIC;
/*Data for the table `account_info` */
insert into
account_info(id,account_name,account_no ,account_password,account_balance) values
(2,'张三','1',NULL,1000);
bank2库,包含李四账户
CREATE DATABASE /*!32312 IF NOT EXISTS*/bank2
/*!40100 DEFAULT CHARACTER SET utf8 */;
USE bank2;
/*Table structure for table account_info */
DROP TABLE IF EXISTS account_info;
CREATE TABLE account_info (
id bigint(20) NOT NULL AUTO_INCREMENT,
account_name varchar(100) COLLATE utf8_bin DEFAULT NULL COMMENT '户主姓名',
account_no varchar(100) COLLATE utf8_bin DEFAULT NULL COMMENT '银行卡号',
account_password varchar(100) COLLATE utf8_bin DEFAULT NULL COMMENT '帐户密码', account_balance double DEFAULT NULL COMMENT '帐户余额',
PRIMARY KEY (id) USING BTREE) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT
CHARSET=utf8 COLLATE=utf8_bin ROW_FORMAT=DYNAMIC;
/*Data for the table `account_info` */
insert into account_info(id,account_name,account_no,account_password,account_balance) values(3,'李四','2',NULL,0);
🔥Seata提供XA模式实现分布式事务_下载启动Seata服务
下载seata服务器
下载地址:https://github.com/seata/seata/releases
解压并启动
tar -zxvf seata-server-1.4.2.tar.gz -C
/usr/local/
#后台运行
nohup sh seata-server.sh -p 9999 -h
192.168.66.100 -m file &> seata.log &
注意:
其中9999为服务端口号;file为启动模式,这里指seata服务将采用文件的方式存储信息。
测试
查看启动日志
cat seata.log
🔥Seata提供XA模式实现分布式事务_搭建聚合父工程构建
创建工程distribute-transaction
字符编码
注解生效激活
Java编译版本选择
<!-- 指定JDK版本--><build><plugins><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-compiler-plugin</artifactId><configuration><source>1.8</source><target>1.8</target><encoding>UTF-8</encoding></configuration></plugin></plugins></build>
File Type过滤
pom配置版本
<properties><spring-boot.version>2.6.3</springboot.version><spring.cloud.version>2021.0.1</spring.cloud.version><spring.cloud.alibaba.version>2021.0.1.0</spring.cloud.alibaba.version><lombok.version>1.18.22</lombok.version></properties><dependencyManagement><dependencies><!--spring boot 2.6.3--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-bootstarter-parent</artifactId><version>${spring-boot.version}
</version><type>pom</type><scope>import</scope></dependency><!-- SpringCloud --><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-clouddependencies</artifactId><version>${spring.cloud.version}</version><type>pom</type><scope>import</scope></dependency><!-- SpringCloud Aliabab --><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-alibaba-dependencies</artifactId><version>${spring.cloud.alibaba.version}
</version><type>pom</type><scope>import</scope></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>${lombok.version}
</version></dependency></dependencies></dependencyManagement>
IDEA开启Dashboard
普通的Run面板
Run Dashboard面板
修改配置文件
在.idea/workspace.xml 文件中找到
添加配置
<component name="RunDashboard"><option name="ruleStates"><list><RuleState><option name="name"
value="ConfigurationTypeDashboardGroupingRule"/></RuleState><RuleState><option name="name"
value="StatusDashboardGroupingRule" /></RuleState></list></option><option name="configurationTypes"><set><option value="SpringBootApplicationConfigurationType"/></set>
</option>
</component>
🔥Seata提供XA模式实现分布式事务_转账功能实现上
实现如下功能
⭐李四账户增加金额。
创建bank2
pom引入依赖
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starterweb</artifactId></dependency><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-bootstarter</artifactId><version>3.5.1</version></dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connectorjava</artifactId><version>5.1.49</version></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></dependency><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starteralibaba-nacos-discovery</artifactId></dependency>
编写主启动类
//添加对mapper包扫描 Mybatis-plus
@MapperScan("com.it.mapper")
@SpringBootApplication
@Slf4j
//开启发现注册
@EnableDiscoveryClient
public class SeataBank2Main6002 {public static void main(String[] args) {SpringApplication.run(SeataBank1Main6002.class
,args);log.info("**************
SeataBank1Main6002 *************");}
}
编写YML配置文件
server:port: 6002
spring:application:name: seata-bank2
cloud:nacos:discovery:# Nacos server地址server-addr: 192.168.66.101:8848datasource:url: jdbc:mysql://localhost:3306/bank2?
useUnicode=true&characterEncoding=utf-
8&useSSL=false&serverTimezone=UTCusername: rootpassword: 123456driver-class-name: com.mysql.jdbc.Driver
代码生成
引入Mybatis Plus代码生成依赖
<dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plusgenerator</artifactId><version>3.5.2</version></dependency><!-- 模板引擎 --><dependency><groupId>org.apache.velocity</groupId><artifactId>velocity-enginecore</artifactId><version>2.0</version></dependency>
生成代码
package com.it.utils;
import
com.baomidou.mybatisplus.generator.FastAutoGenerator;
import
com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
import java.util.Arrays;
import java.util.List;
public class CodeGenerator {public static void main(String[] args) {FastAutoGenerator.create("jdbc:mysql://192.168.66.100:3306/bank2", "root", "123456").globalConfig(builder -> {builder.author("it")
// 设置作者.commentDate("MM-dd") // 注释日期格式.outputDir(System.getProperty("user.dir")+
"/xa-seata/bank2"+ "/src/main/java/") // 指定输出目录.fileOverride(); // 覆盖文件})// 包配置.packageConfig(builder -> {
builder.parent("com.it") // 包名前缀.entity("entity")
//实体类包名.mapper("mapper")
//mapper接口包名.service("service"); //service包名}).strategyConfig(builder -> {// 设置需要生成的表名List<String> strings =
Arrays.asList("account_info");builder.addInclude(strings)
// 开始实体类配置
.entityBuilder()
// 开启lombok模型
.enableLombok()
//表名下划线转驼峰
.naming(NamingStrategy.underline_to_camel)
//列名下划线转驼峰
.columnNaming(NamingStrategy.underline_to_camel
);}).execute();}
}
编写转账接口
public interface IAccountInfoService {//李四增加金额void updateAccountBalance(String accountNo,Double amount);
}
编写转账接口实现类
@Service
@Slf4j
public class AccountInfoServiceImpl implements IAccountInfoService {@AutowiredAccountMapper accountMapper;@Overridepublic void updateAccountBalance(String
accountNo, Double amount) {// 1. 获取用户信息AccountInfo accountInfo =
accountMapper.selectById(accountNo);accountInfo.setAccountBalance(accountInfo.getAccountBalance() + amount);accountMapper.updateById(accountInfo);}
}
编写控制层
@RestController
@RequestMapping("/bank2")
public class Bank2Controller {@AutowiredIAccountInfoService accountInfoService;//接收张三的转账@GetMapping("/transfer")public String transfer(Double amount){//李四增加金额accountInfoService.updateAccountBalance("3",amount);return "bank2"+amount;}
}
🔥Seata提供XA模式实现分布式事务_转账功能实现下
实现如下功能
⭐张三账户减少金额
⭐远程调用bank2向李四转账。
pom引入依赖
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-bootstarter</artifactId><version>3.5.1</version></dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connectorjava</artifactId><version>5.1.49</version></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></dependency><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starteralibaba-nacos-discovery</artifactId></dependency><!-- openfeign --><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starteropenfeign</artifactId></dependency><dependency>
<groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starterloadbalancer</artifactId></dependency>
编写主启动类
//添加对mapper包扫描 Mybatis-plus
@MapperScan("com.it.mapper")
//开启OpenFiegn
@EnableFeignClients
@SpringBootApplication
@Slf4j
//开启发现注册
@EnableDiscoveryClient
public class SeataBank1Main6001 {public static void main(String[] args) {SpringApplication.run(SeataBank1Main6001.class,args);log.info("**************
SeataBank1Main6001 *************");}
}
编写YML配置文件
server:port: 6001
spring:application:name: seata-bank1cloud:nacos:discovery:# Nacos server地址server-addr: 192.168.66.101:8848datasource:url: jdbc:mysql://localhost:3306/bank1?
useUnicode=true&characterEncoding=utf-
8&useSSL=true&serverTimezone=UTCusername: rootpassword: 123456driver-class-name: com.mysql.jdbc.Driver
创建实体类
@AllArgsConstructor
@NoArgsConstructor
@Builder
@TableName("account_info")
@Data
public class AccountInfo {//id@TableIdprivate Long id;//户主姓名@TableField("account_name")private String accountName;//银行卡号@TableField("account_no")private String accountNo;//账户密码@TableField("account_password")private String accountPassword;//账户余额@TableField("account_balance")private Double accountBalance;
}
编写持久层
@Component
@Mapper
public interface AccountMapper extends
BaseMapper<AccountInfo> {
}
编写转账接口
public interface IAccountInfoService {//张三扣减金额public void updateAccountBalance(String
accountNo, Double amount);
}
编写远程调用接口
@Component
@FeignClient(value="seata-bank2")
public interface Bank2Client {//远程调用李四的微服务@GetMapping("/bank2/transfer")String transfer(@RequestParam("amount")
Double amount);
}
编写转账接口实现类
@Service
@Slf4j
public class AccountInfoServiceImpl implements IAccountInfoService {@AutowiredAccountMapper accountMapper;@AutowiredBank2Client bank2Client;@Overridepublic void updateAccountBalance(String
accountNo, Double amount) {// 1. 获取用户信息AccountInfo accountInfo =
accountMapper.selectById(2);// 2. 判断张三账户余额是否有钱if (accountInfo.getAccountBalance() >
amount){//扣减张三的金额accountInfo.setAccountBalance(accountInfo.getAccountBalance()-amount);int result =
accountMapper.updateById(accountInfo);if (result!=0){//调用李四微服务,转账bank2Client.transfer(amount);}}}
}
编写控制层
@RestController
public class Bank1Controller {@AutowiredIAccountInfoService IAccountInfoService;//张三转账@GetMapping("/transfer")public String transfer(Double amount){IAccountInfoService.updateAccountBalance("1",amount);return "bank1"+amount;}}