1. 项目概述
最近在重构公司的一个分布式微服务系统时,遇到了一个棘手的问题:跨服务的数据一致性如何保证?经过技术调研,我们最终选择了Seata这个开源的分布式事务解决方案。本文将分享Spring Boot 3.2.5与Seata 1.8.0的完整整合过程,包含我在实际项目中踩过的坑和优化经验。
Seata作为阿里巴巴开源的分布式事务中间件,提供了AT、TCC、SAGA和XA四种事务模式。我们主要使用AT模式,它通过对业务代码零侵入的方式,解决了微服务架构下的数据一致性问题。Spring Boot 3.2.5作为当前最新的稳定版本,在性能和安全方面都有显著提升,与Seata 1.8.0的整合需要特别注意一些版本适配问题。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 环境准备与依赖配置
2.1 基础环境要求
在开始整合前,需要确保开发环境满足以下条件:
- JDK 17+(Spring Boot 3.x的最低要求)
- Maven 3.6.3+或Gradle 7.x
- MySQL 5.7+/PostgreSQL(作为业务数据库)
- Nacos 2.x(作为Seata的配置和注册中心)
- Seata Server 1.8.0
注意:Seata 1.8.0对JDK的要求是1.8+,但Spring Boot 3.x需要JDK 17+,这个版本差异需要特别注意。
2.2 Maven依赖配置
在Spring Boot项目的pom.xml中添加以下关键依赖:
xml复制<!-- Seata Starter -->
<dependency>
<groupId>io.seata</groupId>
<artifactId>seata-spring-boot-starter</artifactId>
<version>1.8.0</version>
</dependency>
<!-- Spring Cloud Alibaba -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-seata</artifactId>
<version>2022.0.0.0</version>
<exclusions>
<exclusion>
<groupId>io.seata</groupId>
<artifactId>seata-spring-boot-starter</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- 数据库相关 -->
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.5.3.1</version>
</dependency>
2.3 Seata Server部署
Seata Server的部署有几种方式:
- 直接下载二进制包运行
- 通过Docker容器部署
- 源码编译运行
这里以Docker方式为例:
bash复制docker run -d --name seata-server \
-p 8091:8091 \
-p 7091:7091 \
-e SEATA_IP=your_server_ip \
-e SEATA_PORT=8091 \
-e STORE_MODE=db \
-e DB_HOST=mysql_host \
-e DB_PORT=3306 \
-e DB_USER=seata \
-e DB_PASSWORD=seata \
seataio/seata-server:1.8.0
3. 核心配置详解
3.1 application.yml配置
Spring Boot应用的配置文件需要添加以下Seata相关配置:
yaml复制spring:
cloud:
alibaba:
seata:
tx-service-group: my_tx_group # 事务组名称,需与seata-server配置一致
seata:
enabled: true
application-id: ${spring.application.name}
tx-service-group: my_tx_group
service:
vgroup-mapping:
my_tx_group: default # 映射到seata-server的默认组
grouplist:
default: 127.0.0.1:8091
registry:
type: nacos
nacos:
server-addr: 127.0.0.1:8848
namespace: public
group: SEATA_GROUP
config:
type: nacos
nacos:
server-addr: 127.0.0.1:8848
namespace: public
group: SEATA_GROUP
3.2 数据库表结构准备
Seata的AT模式需要在业务数据库中创建undo_log表:
sql复制CREATE TABLE IF NOT EXISTS `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,
PRIMARY KEY (`id`),
UNIQUE KEY `ux_undo_log` (`xid`, `branch_id`)
) ENGINE = InnoDB
AUTO_INCREMENT = 1
DEFAULT CHARSET = utf8;
同时需要在Seata Server的配置数据库中创建全局事务表:
sql复制-- seata-server数据库中的表结构
CREATE TABLE IF NOT EXISTS `global_table`
(
`xid` VARCHAR(128) NOT NULL,
`transaction_id` BIGINT,
`status` TINYINT NOT NULL,
`application_id` VARCHAR(32),
`transaction_service_group` VARCHAR(32),
`transaction_name` VARCHAR(128),
`timeout` INT,
`begin_time` BIGINT,
`application_data` VARCHAR(2000),
`gmt_create` DATETIME,
`gmt_modified` DATETIME,
PRIMARY KEY (`xid`),
KEY `idx_gmt_modified_status` (`gmt_modified`, `status`),
KEY `idx_transaction_id` (`transaction_id`)
) ENGINE = InnoDB
DEFAULT CHARSET = utf8;
-- 分支事务表、锁表等省略...
4. 代码实现与事务使用
4.1 全局事务注解使用
在需要分布式事务的方法上添加@GlobalTransactional注解:
java复制@Service
public class OrderServiceImpl implements OrderService {
@Autowired
private AccountFeignClient accountFeignClient;
@Autowired
private StorageFeignClient storageFeignClient;
@GlobalTransactional(name = "createOrder", timeoutMills = 60000, rollbackFor = Exception.class)
@Override
public void createOrder(OrderDTO orderDTO) {
// 1. 创建订单
orderMapper.insert(orderDTO);
// 2. 扣减库存(远程调用)
storageFeignClient.deduct(orderDTO.getCommodityCode(), orderDTO.getCount());
// 3. 扣减账户余额(远程调用)
accountFeignClient.debit(orderDTO.getUserId(), orderDTO.getMoney());
// 如果以上任何一步失败,整个事务都会回滚
}
}
4.2 Feign客户端配置
对于使用Feign进行服务间调用的场景,需要确保请求头中的事务信息能够传递:
java复制@Configuration
public class FeignConfig {
@Bean
public RequestInterceptor seataFeignInterceptor() {
return template -> {
String xid = RootContext.getXID();
if (StringUtils.isNotBlank(xid)) {
template.header(RootContext.KEY_XID, xid);
}
};
}
}
4.3 MyBatis-Plus集成
如果使用MyBatis-Plus作为ORM框架,需要配置Seata的SQL拦截器:
java复制@Configuration
public class MybatisPlusConfig {
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor(DataSource dataSource) {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
// 添加Seata的SQL拦截器
interceptor.addInnerInterceptor(new SeataInnerInterceptor(dataSource));
// 其他拦截器...
return interceptor;
}
}
5. 常见问题与解决方案
5.1 事务不生效排查
-
检查点1:注解是否生效
- 确保@GlobalTransactional注解添加在public方法上
- 确保方法是通过Spring代理调用的(直接调用同类方法不会触发AOP)
-
检查点2:XID传递
- 使用日志打印RootContext.getXID(),确认事务ID是否正确传递
- 在Feign调用前后检查请求头中是否有"xid"字段
-
检查点3:数据库支持
- 确认业务数据库是Seata支持的MySQL、PostgreSQL等
- 确认undo_log表已正确创建
5.2 性能优化建议
-
客户端优化:
- 调整seata.client.tm.degrade-check-period为较大值(默认10秒)
- 设置seata.client.tm.degrade-check-allow-times=5(默认10次)
-
服务端优化:
- 对于高并发场景,建议使用redis作为存储模式
- 调整server.session.branch-async-queue-size(默认5000)
-
SQL优化:
- 避免在事务中执行大查询
- 合理设置事务超时时间
5.3 版本兼容性问题
Spring Boot 3.x与Seata 1.8.0整合时需要注意:
-
JDK版本问题
- Seata 1.8.0最低要求JDK 1.8
- Spring Boot 3.x要求JDK 17+
- 解决方案:统一使用JDK 17+
-
Spring Cloud Alibaba版本
- 推荐使用2022.0.0.0版本
- 需要排除旧版seata-starter依赖
-
Jackson版本冲突
- Spring Boot 3.x使用Jackson 2.15+
- 可能需要排除旧版本Jackson依赖
6. 高级配置与扩展
6.1 多数据源配置
对于多数据源场景,需要为每个数据源配置Seata代理:
java复制@Configuration
public class DataSourceConfig {
@Bean
@ConfigurationProperties(prefix = "spring.datasource.master")
public DataSource masterDataSource() {
return new DruidDataSource();
}
@Bean
public DataSourceProxy masterDataSourceProxy(@Qualifier("masterDataSource") DataSource dataSource) {
return new DataSourceProxy(dataSource);
}
@Bean
public SqlSessionFactory masterSqlSessionFactory(
@Qualifier("masterDataSourceProxy") DataSourceProxy dataSourceProxy) throws Exception {
MybatisSqlSessionFactoryBean factoryBean = new MybatisSqlSessionFactoryBean();
factoryBean.setDataSource(dataSourceProxy);
return factoryBean.getObject();
}
}
6.2 自定义事务隔离级别
Seata默认使用读已提交(RC)隔离级别,如需修改:
java复制@Configuration
public class SeataConfig {
@Bean
public GlobalTransactionScanner globalTransactionScanner() {
return new GlobalTransactionScanner("your-app-name", "your-tx-group") {
@Override
protected void initClient() {
// 设置隔离级别为读未提交(RU)
TMConfiguration.setClientAsyncCommitBufferLimit(1000);
TMConfiguration.setClientLockRetryPolicyBranchRollbackOnConflict(true);
TMConfiguration.setClientLockRetryInterval(10);
TMConfiguration.setClientLockRetryTimes(30);
super.initClient();
}
};
}
}
6.3 监控与运维
-
Seata控制台
- 部署Seata控制台服务监控事务状态
- 访问http://localhost:7091查看全局事务
-
Prometheus监控
- Seata Server内置Prometheus metrics
- 配置示例:
yaml复制metrics: enabled: true registry-type: compact exporter-list: prometheus exporter-prometheus-port: 9898
-
日志分析
- 建议将Seata Server日志接入ELK
- 关键日志路径:logs/seata/global.log
7. 生产环境最佳实践
经过多个项目的实战检验,总结以下生产环境建议:
-
- Seata Server建议3节点集群部署
- 使用Nginx做负载均衡
- 数据库建议使用主从架构
-
参数调优
yaml复制seata: client: rm: report-retry-count: 5 table-meta-check-enable: false tm: commit-retry-count: 5 rollback-retry-count: 5 service: disable-global-transaction: false -
灾备方案
- 定期备份seata-server的数据库
- 准备手动事务恢复脚本
- 实现事务状态监控告警
-
压测建议
- 建议在预发布环境进行全链路压测
- 关注undo_log表的增长情况
- 监控Seata Server的CPU和内存使用率
在实际项目中,我们发现当TPS超过2000时,Seata Server会成为性能瓶颈。这时可以考虑以下优化:
- 将store.mode从db改为redis
- 增加Seata Server节点数
- 适当增大server.session.branch-async-queue-size
另外,对于特别关键的业务,建议实现TCC模式作为备用方案。虽然代码侵入性较强,但性能更好,适合高并发场景。
