指示:https://sca.aliyun.com/docs/2025.x/user-guide/seata/quick-start/?spm=5176.29160081.0.0.509a5c721QzaKQ
安装seata需要的库表
CREATE DATABASE seata;
USE seata;
导入 seata-SERVER db 模式所需要的数据库表
在数据库中初始化 global_table、branch_table、lock_table、distributed_lock。
-- -------------------------------- The script used when storeMode is 'db' --------------------------------
-- the table to store GlobalSession data
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_status_gmt_modified` (`status` , `gmt_modified`),
KEY `idx_transaction_id` (`transaction_id`)
) ENGINE = INNODB
DEFAULT CHARSET = utf8mb4;
-- the table to store BranchSession data
CREATE TABLE IF NOT EXISTS `branch_table`
(
`branch_id` BIGINT NOT NULL,
`xid` VARCHAR(128) NOT NULL,
`transaction_id` BIGINT,
`resource_group_id` VARCHAR(32),
`resource_id` VARCHAR(256),
`branch_type` VARCHAR(8),
`status` TINYINT,
`client_id` VARCHAR(64),
`application_data` VARCHAR(2000),
`gmt_create` DATETIME(6),
`gmt_modified` DATETIME(6),
PRIMARY KEY (`branch_id`),
KEY `idx_xid` (`xid`)
) ENGINE = INNODB
DEFAULT CHARSET = utf8mb4;
-- the table to store lock data
CREATE TABLE IF NOT EXISTS `lock_table`
(
`row_key` VARCHAR(128) NOT NULL,
`xid` VARCHAR(128),
`transaction_id` BIGINT,
`branch_id` BIGINT NOT NULL,
`resource_id` VARCHAR(256),
`table_name` VARCHAR(32),
`pk` VARCHAR(36),
`status` TINYINT NOT NULL DEFAULT '0' COMMENT '0:locked ,1:rollbacking',
`gmt_create` DATETIME,
`gmt_modified` DATETIME,
PRIMARY KEY (`row_key`),
KEY `idx_status` (`status`),
KEY `idx_branch_id` (`branch_id`),
KEY `idx_xid` (`xid`)
) ENGINE = INNODB
DEFAULT CHARSET = utf8mb4;
CREATE TABLE IF NOT EXISTS `distributed_lock`
(
`lock_key` CHAR(20) NOT NULL,
`lock_value` VARCHAR(20) NOT NULL,
`expire` BIGINT,
PRIMARY KEY (`lock_key`)
) ENGINE = INNODB
DEFAULT CHARSET = utf8mb4;
INSERT INTO `distributed_lock` (lock_key, lock_value, expire) VALUES ('AsyncCommitting', ' ', 0);
INSERT INTO `distributed_lock` (lock_key, lock_value, expire) VALUES ('RetryCommitting', ' ', 0);
INSERT INTO `distributed_lock` (lock_key, lock_value, expire) VALUES ('RetryRollbacking', ' ', 0);
INSERT INTO `distributed_lock` (lock_key, lock_value, expire) VALUES ('TxTimeoutCheck', ' ', 0);
seata2.5新增一张表
CREATE TABLE IF NOT EXISTS vgroup_table (
id BIGINT NOT NULL AUTO_INCREMENT,
vgroup VARCHAR(255) NOT NULL,
`namespace` VARCHAR(255) DEFAULT NULL,
cluster VARCHAR(255) NOT NULL,
gmt_create DATETIME DEFAULT NULL,
gmt_modified DATETIME DEFAULT NULL,
PRIMARY KEY (id),
UNIQUE KEY uidx_vgroup_namespace (vgroup, `namespace`)
) ENGINE = INNODB DEFAULT CHARSET = utf8mb4;
INSERT INTO vgroup_table (vgroup, namespace, cluster)
VALUES ('default_tx_group', 'public', 'default');
配置 UNDO_LOG 表,这张表要建在每个有事务发生的库中,而不是在seata库中
Seata AT 模式需要使用到 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;
podman安装seata-server2.5.0
1)配置文件
1.1)编辑 vim /home/wt/seata/resources/application.yml,并保存
server:
port: 8091
spring:
application:
name: seata-server
main:
web-application-type: none
logging:
config: classpath:logback-spring.xml
file:
path: ${log.home:${user.home}/logs/seata}
extend:
logstash-appender:
# off by default
enabled: false
destination: 127.0.0.1:4560
kafka-appender:
# off by default
enabled: false
bootstrap-servers: 127.0.0.1:9092
topic: logback_to_logstash
producer:
acks: 0
linger-ms: 1000
max-block-ms: 0
metric-appender:
# off by default
enabled: false
seata:
security:
# 必须与 seata-naming-server 的 secretKey 完全一致
secretKey: 'ohix3cki1W7QwiCAG9xrNa0mAksxBJ17vmBN0zaeZ+g='
# Token有效期(毫秒),可按需调整
tokenValidityInMilliseconds: 1800000
registry:
type: nacos,seata #同时启动两种类型,用,分隔
nacos:
application: seata-server
server-addr: 192.168.0.101:8848
namespace: c2e34049-e03c-44ec-9e36-a2e7bbb47951
data-id: seataServer.properties # 关键:指向Nacos中的配置
group: SEATA_GROUP
username: nacos # 👈 新增
password: nacos # 👈 新增
seata:
# NamingServer 的地址和端口
server-addr: seata-naming-server:8081
# 命名空间,需与 NamingServer 配置一致
namespace: public
# 集群名称,需与 NamingServer 配置一致
cluster: default
# 心跳间隔(毫秒)
heartbeat-period: 5000
config:
type: nacos
nacos:
server-addr: 192.168.0.101:8848
namespace: c2e34049-e03c-44ec-9e36-a2e7bbb47951
group: SEATA_GROUP
data-id: seataServer.properties # 关键:指向Nacos中的配置
username: nacos
password: nacos
1.2)nacos中添加seata-server的关于数据库的配置
service.vgroupMapping.default_tx_group=default store.mode=db store.db.datasource=druid store.db.dbType=mysql store.db.driverClassName=com.mysql.cj.jdbc.Driver store.db.url=jdbc:mysql://mysql-master:3306/seata?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true store.db.user=root store.db.password=root store.db.minConn=5 store.db.maxConn=100 store.db.globalTable=global_table store.db.branchTable=branch_table store.db.lockTable=lock_table store.db.distributedLockTable=distributed_lock store.db.queryLimit=100 server.console.enabled=true server.console.port=7091 logging.level.org.apache.seata.discovery=DEBUG logging.level.org.apache.seata.common.util.HttpClientUtil=DEBUG
2) 根据mysql版本,准备相应的jar
/home/wt/seata/mysql-connector-java-5.1.47.jar
/home/wt/seata/mysql-connector-j-8.4.0.jar
3)启动容器
podman stop seata-server podman rm seata-server podman run -d --name seata-server \ --network mysql-net \ -p 8091:8091 -p 7091:7091 \ -e SEATA_IP=192.168.0.101 \ -e TZ=Asia/Shanghai \ -v /home/wt/seata/resources/application.yml:/seata-server/resources/application.yml \ -v /home/wt/seata/mysql-connector-j-8.4.0.jar:/seata-server/libs/mysql-connector-j-8.4.0.jar \ apache/seata-server:2.5.0
4)查看启动状况
wt@wt-PU451LD:~/seata$ podman logs -f seata-server
配置web观察事务控制台seata-namingserver
1)本机上seata-namingserver配置文件
vim /home/wt/seata/seata-namingserver/conf/application.yml
server:
port: 8081
spring:
application:
name: seata-namingserver
logging:
file:
path: /logs/seata
seata:
security:
# JWT签名密钥,必须是Base64编码 openssl rand -base64 32 这个命令生成
secretKey: 'ohix3cki1W7QwiCAG9xrNa0mAksxBJ17vmBN0zaeZ+g=' #要与seata-server中的一致
# Token有效期(毫秒)
tokenValidityInMilliseconds: 1800000 #要与seata-server中的一致
namingserver:
metrics:
enabled: true
# ============ 顶层 console 配置(关键!)============
console:
user:
username: seata
password: seata # 这里设置固定的控制台登录密码
2) 启动容器:
podman run -d --name seata-naming-server \ --network mysql-net \ -p 8081:8081 \ -e TZ=Asia/Shanghai \ -v /home/wt/seata/seata-namingserver/conf/application.yml:/seata-naming-server/resources/application.yml \ apache/seata-naming-server:2.5.0
3)访问
可以通过:http://192.168.0.101:8081/访问web界面。当有事务发生时就可以观察到
=============================================================================================
总结一下:nacos,seata-server,NamingServer之间的关系
=============================================================================================
在 Seata 2.5.0 的架构中,这三个组件的关系确实是理解配置的关键。我结合你项目的实际情况,梳理一下。
🎯 一句话概括
| 组件 | 角色 |
|---|---|
| Nacos | 通用的服务注册与配置中心(Spring Cloud 生态的"通讯录") |
| Seata Server (TC) | 分布式事务协调器(事务的总指挥) |
| NamingServer | Seata 原生的注册中心 + 控制台(Seata 2.4+ 引入,用于替代旧版 Seata Server 内置的控制台) |
📐 三者的关系图
┌─────────────────────────────────────────────────────────┐
│ 微服务(order / storage / account) │
│ ├── 业务服务注册到 Nacos(服务发现) │
│ └── 作为 Seata TM/RM 连接到 Seata Server (8091) │
└─────────────────────────────────────────────────────────┘
│ 注册到 Nacos │ RPC (8091)
↓ ↓
┌──────────────────┐ ┌──────────────────────┐
│ Nacos │ │ Seata Server (TC) │
│ (8848) │ │ (8091) │
│ │ │ │
│ 服务注册中心 │ │ 事务协调器 │
│ 配置中心 │ │ 存储:db │
└──────────────────┘ └──────────────────────┘
↑ │
│ 注册到 Nacos │ 注册到 NamingServer
│ ↓
│ ┌──────────────────────┐
└──────────────│ NamingServer │
│ (8081) │
│ │
│ 原生注册中心 │
│ 控制台 UI │
└──────────────────────┘
🔍 三者的具体分工
1. Nacos —— 通用注册中心 + 配置中心
它做什么:
-
让微服务之间互相发现(order 找 storage、account 用 Nacos)
-
存放 Seata Server 的配置(
seataServer.properties,包括 store.mode=db、数据库连接、vgroup 映射等)
谁注册到 Nacos:
-
微服务(
seata-order-service、seata-storage-service等) -
Seata Server(作为服务注册进去,方便微服务通过 Nacos 发现它)
你的配置:
-
Seata Server 的
seataServer.properties就存在 Nacos 的DEFAULT_GROUP下 -
你通过
registry.conf的config.nacos.dataId指向它
2. Seata Server (TC) —— 事务协调器
它做什么:
-
接收微服务的 TM 注册(全局事务发起者)
-
接收微服务的 RM 注册(分支事务参与者)
-
协调全局事务的提交或回滚
-
用
db模式时,把事务数据写入 MySQL 的global_table、branch_table
它连接到谁:
-
通过
registry.nacos注册到 Nacos(服务发现) -
通过
registry.seata注册到 NamingServer(Seata 原生注册中心) -
通过
config.nacos从 Nacos 拉取业务配置
你的配置:
-
registry.conf里的type = "nacos,seata"表示同时注册到两个中心 -
application.yml主要放 Spring Boot 级别配置
3. NamingServer —— Seata 原生注册中心 + 控制台
它做什么:
-
替代旧版 Seata Server 内置的控制台(2.4 版本起移除)
-
作为 Seata 原生注册中心,让 Seata Server 注册到它上面
-
提供事务查询 UI:
http://192.168.0.101:8081 -
通过
/naming/v1/clusters等 API 查询实例列表
它的数据来源:
-
不直接查数据库!它通过 RPC/HTTP 调用 Seata Server 的接口来获取事务数据
-
所以 Seata Server 必须注册到 NamingServer,控制台才能显示数据
你的配置:
-
console.user是控制台登录凭据 -
seata.security.secretKey用于 JWT 认证
⚠️ 常见误区
误区 1:NamingServer 需要配 seata.registry.nacos 去发现 Seata Server
❌ 错。NamingServer 本身就是注册中心,它不主动"发现"谁,而是Seata Server 主动注册到它。
误区 2:控制台数据来自 NamingServer 直查数据库
❌ 错。NamingServer 通过调用 Seata Server 的 API(默认 8081 或 8091)获取数据,Seata Server 再从 MySQL 查。
误区 3:Nacos 和 NamingServer 二选一
⚠️ 可以共存。两者是独立注册中心,Seata Server 可以同时注册到两个。微服务用 Nacos 发现 Seata Server,NamingServer 用于控制台。
误区 4:registry.conf 和 application.yml 同时改
⚠️ application.yml 优先级更高,会覆盖 registry.conf 的部分配置。改的时候要保证两者不冲突。
🔗 你项目的实际数据流
1. 微服务启动 ├── 注册到 Nacos(服务发现) └── 连接 Seata Server (8091) 注册 TM/RM 2. Seata Server 启动 ├── 从 Nacos 拉配置(seataServer.properties) ├── 用 db 模式连接 MySQL ├── 注册到 Nacos(SEATA_GROUP / seata-server) └── 注册到 NamingServer(public / default) 3. 微服务发起下单事务 ├── TM 在 Seata Server 创建全局事务(XID) ├── 每个 RM 注册分支事务到 Seata Server └── Seata Server 协调提交/回滚 4. 你访问控制台 http://192.168.0.101:8081 ├── NamingServer 从它自己维护的实例列表找到 Seata Server ├── 通过 HTTP 调 Seata Server 的查询接口 └── 展示事务数据
📋 三者配置对应关系
| 配置项 | 存在哪里 | 作用 |
|---|---|---|
store.mode、store.db.url |
Nacos 的 seataServer.properties |
告诉 Seata Server 怎么存数据 |
service.vgroupMapping |
Nacos 或 vgroup_table |
事务分组映射 |
registry.nacos.* |
Seata Server 的 registry.conf |
Seata Server 注册到 Nacos |
registry.seata.* |
Seata Server 的 registry.conf |
Seata Server 注册到 NamingServer |
console.user.* |
NamingServer 的 application.yml |
控制台登录凭据 |
seata.security.secretKey |
两边都要配(必须一致) | JWT 签名密钥 |
seata.registry.nacos.* |
微服务的 application.yml |
微服务通过 Nacos 发现 Seata Server |
🎯 你现在的问题
Seata Server 没有注册到 NamingServer,导致控制台的实例列表为空([])。
排查方向:
-
registry.conf中seata块的字段名是否正确(server-addrvsserverAddr) -
application.yml是否覆盖了registry.conf的注册配置 -
type = "nacos,seata"逗号语法在 2.5.0 是否真的支持
💎 总结
| 关系 | 说明 |
|---|---|
| Nacos ↔ 微服务 | 微服务通过 Nacos 互相发现 |
| Nacos ↔ Seata Server | Seata Server 注册到 Nacos,并从 Nacos 拉配置 |
| NamingServer ↔ Seata Server | Seata Server 注册到 NamingServer,供控制台查询 |
| NamingServer ↔ 微服务 | 无直接关系,微服务不需要知道 NamingServer |
| NamingServer ↔ 控制台 | 浏览器访问 NamingServer,它再去 Seata Server 查数据 |
记忆口诀:
-
Nacos = 微服务的"通讯录" + Seata 的"配置仓库"
-
Seata Server = 事务的"总指挥"
-
NamingServer = Seata 的"原生通讯录" + "控制台"
你现在的关键任务:让 Seata Server 成功注册到 NamingServer。建议直接在 application.yml 中配置 seata.registry.type = seata,因为 application.yml 优先级高于 registry.conf。
浙公网安备 33010602011771号