分布式事务协调器 Seata 在生产环境中通常需要将事务日志存储到数据库中以确保高可用性。本文将深入探讨如何正确配置 Seata Server 1.4.2 使用 MySQL 作为存储后端,特别是针对 MySQL 8.0 驱动与 5.x 驱动的关键差异点,提供从环境准备到故障排查的完整解决方案。
在开始配置前,我们需要明确几个核心概念和准备工作。Seata 支持三种存储模式:file(文件系统)、db(数据库)和 redis。对于生产环境,db 模式是最为推荐的选择,它能提供更好的可靠性和可扩展性。
必备组件清单:
对于 MySQL 驱动选择,需要特别注意版本兼容性:
| MySQL 版本 | 推荐驱动类名 | 连接参数要求 |
|---|---|---|
| 5.x | com.mysql.jdbc.Driver | 基础连接字符串 |
| 8.0+ | com.mysql.cj.jdbc.Driver | 需添加时区参数如 serverTimezone |
提示:MySQL 8.0 驱动强制要求时区设置,否则会抛出异常。建议在连接字符串中添加
serverTimezone=Asia/Shanghai参数。
Seata 的 DB 存储模式需要四张核心表来管理分布式事务状态。这些表结构可以在 Seata 源码包的 /script/server/db/mysql.sql 中找到。以下是关键表的用途说明:
建表操作步骤:
sql复制-- 创建 Seata 专用数据库
CREATE DATABASE seata CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci;
-- 执行源码中的 mysql.sql 脚本
USE seata;
SOURCE /path/to/seata/script/server/db/mysql.sql;
对于客户端业务库,每个使用 Seata AT 模式的服务都需要在自己的数据库中创建 undo_log 表:
sql复制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 DEFAULT CHARSET=utf8;
Seata Server 的配置主要通过 seataServer.properties 文件管理。以下是 DB 模式的关键配置项及其作用:
store.db 相关配置:
properties复制# 存储模式设置为 db
store.mode=db
# 数据库连接配置
store.db.datasource=druid
store.db.dbType=mysql
store.db.driverClassName=com.mysql.cj.jdbc.Driver
store.db.url=jdbc:mysql://127.0.0.1:3306/seata?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai
store.db.user=seata_user
store.db.password=secure_password
# 连接池配置
store.db.minConn=5
store.db.maxConn=30
store.db.maxWait=5000
# 表名配置(保持默认即可)
store.db.globalTable=global_table
store.db.branchTable=branch_table
store.db.lockTable=lock_table
store.db.queryLimit=100
事务分组配置(必须与客户端一致):
properties复制service.vgroupMapping.my_tx_group=default
注意:
my_tx_group需要与客户端应用的spring.cloud.alibaba.seata.tx-service-group配置完全一致,否则会出现 "no available server to connect" 错误。
正确配置后,需要通过特定参数启动 Seata Server 以启用 DB 存储模式。在 Windows 和 Linux 环境下启动方式略有不同:
Windows 环境:
bat复制bin\seata-server.bat -m db -h 127.0.0.1 -p 8091
Linux/Unix 环境:
bash复制sh bin/seata-server.sh -m db -h 192.168.1.100 -p 8091
启动参数说明:
-m:指定存储模式(db/file/redis)-h:指定注册到注册中心的IP-p:服务监听端口常见问题排查指南:
驱动类找不到异常:
code复制Caused by: java.lang.ClassNotFoundException: com.mysql.cj.jdbc.Driver
解决方案:将 MySQL Connector/J 8.0+ 的 JAR 包放入 Seata Server 的 lib 目录
时区未配置错误:
code复制The server time zone value 'EDT' is unrecognized...
解决方案:在 JDBC URL 中添加 serverTimezone=Asia/Shanghai 参数
表不存在错误:
code复制Table 'seata.global_table' doesn't exist
解决方案:确认已正确执行 mysql.sql 脚本并检查数据库用户权限
事务分组不匹配:
code复制no available server to connect
解决方案:检查服务端与客户端的 tx-service-group 配置是否一致
对于生产环境部署,建议添加以下监控配置:
properties复制# 启用 Prometheus 监控
metrics.enabled=true
metrics.registryType=compact
metrics.exporterList=prometheus
metrics.exporterPrometheusPort=9898
在高并发场景下,Seata 的 DB 模式需要进行适当的优化配置:
连接池调优建议:
properties复制# 根据并发量调整连接池大小
store.db.minConn=10
store.db.maxConn=100
store.db.maxWait=3000
事务超时配置:
properties复制# 全局事务超时时间(毫秒)
server.maxCommitRetryTimeout=60000
server.maxRollbackRetryTimeout=60000
日志保留策略:
properties复制# 设置 undo 日志保留天数
server.undo.logSaveDays=7
server.undo.logDeletePeriod=86400000
对于 MySQL 8.0 特定优化,建议:
rewriteBatchedStatements=true 参数提升批量操作性能sql复制ALTER TABLE global_table ADD INDEX idx_status_gmt (status, gmt_modified);
ALTER TABLE branch_table ADD INDEX idx_xid_status (xid, status);
在 Kubernetes 或 Docker 环境中部署时,需要注意:
服务端配置完成后,客户端应用需要进行相应调整以确保兼容性:
Spring Boot 应用配置示例:
yaml复制spring:
cloud:
alibaba:
seata:
tx-service-group: my_tx_group
service:
vgroup-mapping:
my_tx_group: default
seata:
registry:
type: nacos
nacos:
server-addr: 127.0.0.1:8848
namespace: ""
group: "SEATA_GROUP"
config:
type: nacos
nacos:
server-addr: 127.0.0.1:8848
namespace: ""
group: "SEATA_GROUP"
dataId: "seataServer.properties"
数据源代理配置(关键步骤):
java复制@Configuration
public class SeataConfig {
@Bean
@ConfigurationProperties(prefix = "spring.datasource")
public DruidDataSource druidDataSource() {
return new DruidDataSource();
}
@Primary
@Bean("dataSource")
public DataSource dataSource(DruidDataSource druidDataSource) {
return new DataSourceProxy(druidDataSource);
}
}
在微服务架构中,还需要特别注意:
实际项目中,我们曾遇到因 Hystrix 线程隔离导致的事务上下文丢失问题,最终通过以下方式解决:
java复制@Aspect
@Component
public class SeataTransactionAspect {
@Before("@within(org.springframework.transaction.annotation.Transactional)")
public void before(JoinPoint joinPoint) {
String xid = RootContext.getXID();
if (StringUtils.hasText(xid)) {
// 显式传递事务上下文
RequestContextHolder.currentRequestAttributes()
.setAttribute("TX_XID", xid, RequestAttributes.SCOPE_REQUEST);
}
}
}