分布式事务难题破解:SpringBoot+Seata实现AT模式全流程解析
🎓博主介绍:Java、Python、js全栈开发 “多面手”,精通多种编程语言和技术,痴迷于人工智能领域。秉持着对技术的热爱与执着,持续探索创新,愿在此分享交流和学习,与大家共进步。
📖DeepSeek-行业融合之万象视界(附实战案例详解100+)
📖全栈开发环境搭建运行攻略:多语言一站式指南(环境搭建+运行+调试+发布+保姆级详解)
👉感兴趣的可以先收藏起来,希望帮助更多的人
分布式事务难题破解:SpringBoot+Seata实现AT模式全流程解析
一、引言
在当今的互联网应用中,分布式系统已经成为主流架构。随着业务的不断发展和系统的不断拆分,分布式事务问题变得愈发突出。分布式事务是指在分布式系统中,多个服务或数据库之间需要保证数据的一致性和完整性。解决分布式事务问题是构建可靠、稳定的分布式系统的关键。
Seata(Simple Extensible Autonomous Transaction Architecture)是一款开源的分布式事务解决方案,提供了 AT、TCC、SAGA 和 XA 等多种事务模式。本文将详细介绍如何使用 Spring Boot 和 Seata 实现 AT 模式的分布式事务,帮助技术人员深入理解和掌握这一解决方案。
二、分布式事务概述
2.1 分布式事务产生的背景
随着互联网业务的快速发展,单体应用逐渐无法满足业务的需求,于是出现了分布式系统架构。在分布式系统中,业务操作往往会涉及多个服务和数据库,每个服务和数据库都有自己的事务管理机制。例如,一个电商系统中的订单服务、库存服务和支付服务可能分别部署在不同的服务器上,当用户下单时,需要同时更新订单表、扣减库存和完成支付,这就涉及到多个服务之间的事务一致性问题。
2.2 常见的分布式事务解决方案
- 两阶段提交(2PC):是一种经典的分布式事务解决方案,分为准备阶段和提交阶段。但它存在性能问题和单点故障问题。
- 三阶段提交(3PC):在 2PC 的基础上增加了一个预准备阶段,一定程度上缓解了 2PC 的单点故障问题,但性能仍然不理想。
- TCC(Try-Confirm-Cancel):将一个业务操作拆分为 Try、Confirm 和 Cancel 三个操作,通过这三个操作来保证事务的一致性。
- SAGA:将一个长事务拆分为多个短事务,每个短事务都有自己的补偿操作,当某个短事务失败时,通过执行补偿操作来保证数据的一致性。
2.3 Seata AT 模式的优势
Seata 的 AT 模式是一种无侵入的分布式事务解决方案,它基于数据库的本地事务和全局事务协调器(TC)来实现分布式事务的管理。AT 模式的主要优势包括:
- 无侵入性:业务代码无需做任何修改,只需要添加 Seata 的注解即可。
- 高性能:AT 模式在执行过程中,只需要在业务操作前后记录相关的日志,不会对业务操作产生太大的性能影响。
- 易用性:Seata 提供了简单易用的 API 和注解,开发人员可以快速上手。
三、Seata 基础介绍
3.1 Seata 架构
Seata 主要由三个组件组成:
- 事务协调器(TC,Transaction Coordinator):维护全局事务的状态,协调并驱动全局事务的提交或回滚。
- 事务管理器(TM,Transaction Manager):定义全局事务的范围,开始全局事务、提交或回滚全局事务。
- 资源管理器(RM,Resource Manager):管理本地资源,负责分支事务的提交和回滚。
3.2 Seata AT 模式原理
AT 模式的执行过程主要分为两个阶段:
- 一阶段:业务 SQL 执行前,Seata 会自动生成回滚日志,记录业务数据在更新前的状态。业务 SQL 执行后,Seata 会记录业务数据在更新后的状态。然后,本地事务提交,释放本地锁和连接资源。
- 二阶段:
- 提交:如果全局事务决定提交,TC 会通知 RM 异步删除一阶段记录的回滚日志。
- 回滚:如果全局事务决定回滚,TC 会通知 RM 根据一阶段记录的回滚日志进行反向补偿操作,将数据恢复到更新前的状态。
四、Spring Boot 集成 Seata AT 模式的环境搭建
4.1 环境准备
- JDK 1.8 及以上
- Maven 3.x
- MySQL 5.7 及以上
- Seata Server 1.4.x 及以上
4.2 搭建 Seata Server
- 下载 Seata Server:从 Seata 的 GitHub 仓库(https://github.com/seata/seata/releases)下载最新版本的 Seata Server。
- 解压并配置:解压下载的文件,进入
conf目录,修改file.conf和registry.conf文件。file.conf配置示例:
service {
vgroupMapping.my_test_tx_group = "default"
default.grouplist = "127.0.0.1:8091"
enableDegrade = false
disableGlobalTransaction = false
}
store {
mode = "db"
db {
datasource = "druid"
dbType = "mysql"
driverClassName = "com.mysql.cj.jdbc.Driver"
url = "jdbc:mysql://127.0.0.1:3306/seata?useUnicode=true&rewriteBatchedStatements=true"
user = "root"
password = "root"
minConn = 5
maxConn = 30
globalTable = "global_table"
branchTable = "branch_table"
lockTable = "lock_table"
queryLimit = 100
maxWait = 5000
}
}
registry.conf配置示例:
registry {
type = "file"
file {
name = "file.conf"
}
}
config {
type = "file"
file {
name = "file.conf"
}
}
- 创建数据库和表:创建一个名为
seata的数据库,并执行conf/db_store.sql文件中的 SQL 语句,创建相关的表。 - 启动 Seata Server:进入
bin目录,执行seata-server.sh(Linux/Mac)或seata-server.bat(Windows)启动 Seata Server。
4.3 创建 Spring Boot 项目
使用 Spring Initializr(https://start.spring.io/)创建一个 Spring Boot 项目,添加以下依赖:
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-seata</artifactId>
<version>2.2.5.RELEASE</version>
</dependency>
</dependencies>
4.4 配置 Seata
在 application.yml 中添加 Seata 相关配置:
spring:
cloud:
alibaba:
seata:
tx-service-group: my_test_tx_group
datasource:
url: jdbc:mysql://127.0.0.1:3306/test?useUnicode=true&rewriteBatchedStatements=true
username: root
password: root
driver-class-name: com.mysql.cj.jdbc.Driver
五、Spring Boot+Seata AT 模式代码实现
5.1 数据库表设计
创建两个数据库表 order 和 stock,分别用于存储订单信息和库存信息。
-- 订单表
CREATE TABLE `order` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`user_id` bigint(20) NOT NULL,
`product_id` bigint(20) NOT NULL,
`count` int(11) NOT NULL,
`amount` decimal(10, 2) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-- 库存表
CREATE TABLE `stock` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`product_id` bigint(20) NOT NULL,
`total` int(11) NOT NULL,
`used` int(11) NOT NULL,
`residue` int(11) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
5.2 实体类定义
创建 Order 和 Stock 实体类:
// Order.java
public class Order {
private Long id;
private Long userId;
private Long productId;
private Integer count;
private BigDecimal amount;
// 省略 getter 和 setter 方法
}
// Stock.java
public class Stock {
private Long id;
private Long productId;
private Integer total;
private Integer used;
private Integer residue;
// 省略 getter 和 setter 方法
}
5.3 DAO 层实现
使用 Spring JDBC Template 实现 OrderDao 和 StockDao:
// OrderDao.java
@Repository
public class OrderDao {
@Autowired
private JdbcTemplate jdbcTemplate;
public void createOrder(Order order) {
String sql = "INSERT INTO `order` (user_id, product_id, count, amount) VALUES (?,?,?,?)";
jdbcTemplate.update(sql, order.getUserId(), order.getProductId(), order.getCount(), order.getAmount());
}
}
// StockDao.java
@Repository
public class StockDao {
@Autowired
private JdbcTemplate jdbcTemplate;
public void decreaseStock(Long productId, Integer count) {
String sql = "UPDATE stock SET total = total - ?, used = used + ?, residue = residue - ? WHERE product_id = ?";
jdbcTemplate.update(sql, count, count, count, productId);
}
}
5.4 Service 层实现
在 OrderService 中使用 @GlobalTransactional 注解开启全局事务:
@Service
public class OrderService {
@Autowired
private OrderDao orderDao;
@Autowired
private StockDao stockDao;
@GlobalTransactional(name = "my_test_tx_group", rollbackFor = Exception.class)
public void createOrder(Long userId, Long productId, Integer count, BigDecimal amount) {
// 创建订单
Order order = new Order();
order.setUserId(userId);
order.setProductId(productId);
order.setCount(count);
order.setAmount(amount);
orderDao.createOrder(order);
// 扣减库存
stockDao.decreaseStock(productId, count);
// 模拟异常
if (true) {
throw new RuntimeException("模拟异常,触发全局事务回滚");
}
}
}
5.5 Controller 层实现
创建 OrderController 提供接口调用:
@RestController
@RequestMapping("/order")
public class OrderController {
@Autowired
private OrderService orderService;
@GetMapping("/create")
public String createOrder(Long userId, Long productId, Integer count, BigDecimal amount) {
try {
orderService.createOrder(userId, productId, count, amount);
return "订单创建成功";
} catch (Exception e) {
return "订单创建失败:" + e.getMessage();
}
}
}
六、测试与验证
6.1 启动项目
启动 Spring Boot 项目和 Seata Server。
6.2 调用接口
使用 Postman 或其他工具调用 http://localhost:8080/order/create?userId=1&productId=1&count=10&amount=100.00 接口。
6.3 验证结果
由于在 OrderService 中模拟了异常,全局事务会回滚,数据库中的订单表和库存表数据不会发生变化。
七、总结与展望
7.1 总结
本文详细介绍了如何使用 Spring Boot 和 Seata 实现 AT 模式的分布式事务。通过 Seata 的 AT 模式,我们可以在不修改业务代码的情况下,轻松解决分布式系统中的事务一致性问题。同时,Seata 的高性能和易用性也为开发人员提供了极大的便利。
7.2 展望
随着分布式系统的不断发展,分布式事务解决方案也将不断完善。未来,Seata 可能会提供更多的事务模式和功能,以满足不同场景的需求。同时,我们也可以将 Seata 与其他技术(如微服务框架、消息队列等)结合使用,构建更加复杂和可靠的分布式系统。
更多推荐

所有评论(0)