Seata提供XA模式实现分布式事务_下载启动Seata服务
下载seata服务器
解压并启动
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-compilerplugin</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</spring-boot.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-cloudalibaba-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.itbaizhan.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:8848 datasource: url: jdbc:mysql://localhost:3306/bank2?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=UTC username: root password01: 123456 driver-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.itbaizhan.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("itxiaotong")// 设置作者 .commentDate("MM-dd") // 注释日期格式 .outputDir(System.getProperty("user.dir")+"/xa-seata/bank2"+ "/src/main/java/") // 指定输出目录 .fileOverride(); //覆盖文件 }) // 包配置 .packageConfig(builder -> { builder.parent("com.itbaizhan") // 包名前缀 .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 { @Autowired AccountMapper accountMapper; @Override public 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 { @Autowired IAccountInfoService accountInfoService; //接收张三的转账 @GetMapping("/transfer") public String transfer(Double amount){ //李四增加金额 accountInfoService.updateAccountBalance("3",amount); return "bank2"+amount; } }
Seata提供XA模式实现分布式事务_转账功能实现下
pom引入依赖
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>3.5.1</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</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-starter-openfeign</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-loadbalancer</artifactId> </dependency>
编写主启动类
//添加对mapper包扫描 Mybatis-plus @MapperScan("com.itbaizhan.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-bank1 cloud: nacos: discovery: # Nacos server地址 server-addr: 192.168.66.101:8848 datasource: url: jdbc:mysql://localhost:3306/bank1?useUnicode=true&characterEncoding=utf-8&useSSL=true&serverTimezone=UTC username: root password01: 123456 driver-class-name: com.mysql.jdbc.Driver
创建实体类
@AllArgsConstructor @NoArgsConstructor @Builder @TableName("account_info") @Data public class AccountInfo { //id @TableId private 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 { @Autowired AccountMapper accountMapper; @Autowired Bank2Client bank2Client; @Override public 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 { @Autowired IAccountInfoService IAccountInfoService; //张三转账 @GetMapping("/transfer") public String transfer(Double amount){ IAccountInfoService.updateAccountBalance("1",amount); return "bank1"+amount; } }
Seata提供XA模式实现分布式事务_没有引入分布式事物问题演示
初始数据库数据
正常情况
发送请求http://localhost:6001/transfer?amount=2
制造异常
在bank2微服务制造异常
异常后测试
发送请求http://localhost:6001/transfer?amount=2
Seata提供XA模式实现分布式事务_项目引入Seata
创建 UNDO_LOG 表
SEATA XA 模式需要 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;
添加依赖
<dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-seata</artifactId> </dependency>
修改配置文件YML
seata: # 注册中心 registry: type: file service: # seata服务端的地址和端口信息,多个使用英文分号分隔 grouplist: default: 192.168.66.100:9999 tx-service-group: my_test_tx_group
bank1微服务开启全局事物
@Transactional
@GlobalTransactional //开启全局事务
bank2开启事物
测试分布式事物
发送请求http://localhost:6001/transfer?amount=2
总结
传统2PC(基于数据库XA协议)和Seata实现2PC的两种2PC方案, 由于Seata的零入侵并且解决了传统2PC长期锁资源的问题,所以推荐采用Seata实现2PC。
XA强一致性分布式事务实战_Atomikos介绍
简单介绍
产品分两个版本:
1、TransactionEssentials:开源的免费产品;
2、ExtremeTransactions:上商业版,需要收费。
这两个产品的关系如下图所示:
什么是JTA
Java事务API(JTA:Java Transaction API)和它的同胞Java事务服 务(JTS:Java Transaction Service),为J2EE平台提供了分布式事务服务(distributed transaction)的能力。
注意:
要想使用用 JTA 事务,那么就需要有一个实现 javax.sql.XADataSource 、 javax.sql.XAConnection 和 javax.sql.XAResource 接口的 JDBC 驱动程序。一个实现了这些 接口的驱动程序将可以参与 JTA 事务。一个 XADataSource 对象就是一个 XAConnection 对象的工厂。XAConnection 是参与 JTA 事务的JDBC 连接。