一、事务基础认知
1.1 本地事务
事务是数据库操作的基本单元,用于保证一组 SQL 语句的原子性执行 ------ 要么全部成功执行并提交,要么全部失败回滚。
数据库事务核心遵循 ACID 原则:
- 原子性(Atomicity):事务是最小执行单位,不可拆分
- 一致性(Consistency):事务执行前后数据状态始终合法
- 隔离性(Isolation):并发事务间相互隔离,互不干扰
- 持久性(Durability):事务提交后,数据修改永久生效
本地事务的实现方式
- 数据库原生控制
sql
START TRANSACTION
-- 保存订单
INSERT INTO tb_order (item_id, num) VALUES (1, 2);
-- 扣减库存
UPDATE tb_item SET num = num - 2 WHERE id = 1;
-- 失败回滚/成功提交
ROLLBACK; -- COMMIT;
- JDBC 编程式事务
java
Connection conn = getConnection();
try {
conn.setAutoCommit(false); // 关闭自动提交
Statement stmt = conn.createStatement();
stmt.executeUpdate("INSERT INTO tb_order ...");
stmt.executeUpdate("UPDATE tb_item ...");
conn.commit(); // 手动提交
} catch (Exception e) {
conn.rollback(); // 异常回滚
} finally {
conn.close();
}
- Spring 声明式事务(AOP)
java
@Transactional // 事务注解
public void insertOrder(TbOrder tbOrder) {
// 保存订单
tbOrderMapper.insertSelective(tbOrder);
// 扣减库存
itemService.updateItem(tbOrder.getItemId(), tbOrder.getNum());
}
1.2 分布式事务
随着微服务架构普及,业务操作往往跨多个服务 / 数据库,此时本地事务无法保证全局一致性,分布式事务应运而生。
分布式事务产生场景
- 跨微服务调用:订单服务调用库存服务扣减库存,跨 JVM 进程
- 跨数据库实例:单体应用操作多个 MySQL 实例(用户库 + 订单库)
- 多服务操作同一数据库:不同服务持有独立数据库连接,仍会产生分布式事务
分布式事务的核心问题
传统本地事务在分布式场景下失效:
java
@Transactional
public void insertOrder(TbOrder tbOrder) {
// 本地保存订单(成功)
tbOrderMapper.insertSelective(tbOrder);
// 远程调用扣减库存(成功)
itemServiceFeign.updateItem(tbOrder.getItemId(), tbOrder.getNum());
// 模拟异常,本地事务回滚,但库存已扣减
int a = 6 / 0;
}
二、分布式事务解决方案 - Seata
2.1 Seata 核心概念
Seata(Simple Extensible Autonomous Transaction Architecture)是阿里开源的分布式事务框架,目标是让分布式事务使用像本地事务一样简单。
核心组件
- TC(Transaction Coordinator):事务协调器,维护全局事务状态,协调提交 / 回滚
- TM(Transaction Manager):事务管理器,定义全局事务范围,发起全局提交 / 回滚
- RM(Resource Manager):资源管理器,管理本地事务,向 TC 注册分支事务
Seata 事务模式
| 模式 | 一致性 | 可用性 | 业务侵入 | 适用场景 |
|---|---|---|---|---|
| XA | 强一致 | 低 | 无 | 金融核心场景 |
| TCC | 最终一致 | 高 | 高 | 定制化业务 |
| AT | 最终一致 | 高 | 无 | 通用业务(默认) |
| SAGA | 最终一致 | 最高 | 中 | 长事务场景 |
2.2 AT 模式工作流程(重点)
AT 模式是 Seata 默认推荐的无侵入方案,分为两个阶段:
一阶段(本地事务提交)
- 解析 SQL,提取表名、条件、修改内容
- 查询前镜像:执行 SQL 前的数据状态
sql
SELECT id, name, num FROM tb_item WHERE id = 1;
- 执行业务 SQL:
UPDATE tb_item SET num = 98 WHERE id = 1; - 查询后镜像:执行 SQL 后的数据状态
- 插入回滚日志到
undo_log表,记录前后镜像与 SQL 信息 - 向 TC 注册分支事务,申请全局锁
- 提交本地事务,上报事务状态给 TC
二阶段
- 回滚 :TC 下发回滚指令,RM 根据
undo_log中的前镜像生成回滚 SQL,恢复数据 - 提交 :TC 下发提交指令,RM 删除
undo_log日志(异步执行,性能高)
2.3 Seata 环境搭建
1. 下载与解压
bash:
# 下载地址:https://github.com/seata/seata/releases
tar -zxvf seata-server-1.4.2.tar.gz -C /usr/local/
2. 配置注册中心(Nacos)
修改conf/registry.conf:
properties:
registry {
type = "nacos"
nacos {
application = "seata-server"
serverAddr = "192.168.204.129:8848"
group = "SEATA_GROUP"
cluster = "default"
}
}
config {
type = "nacos"
nacos {
serverAddr = "192.168.204.129:8848"
group = "SEATA_GROUP"
dataId = "seataServer.properties"
}
}
3. 配置数据源(Nacos 配置中心)
添加配置项seataServer.properties:
properties:
store.mode=db
store.db.dbType=mysql
store.db.url=jdbc:mysql://192.168.61.130:3306/seata?useSSL=false
store.db.user=root
store.db.password=1111
store.db.globalTable=global_table
store.db.branchTable=branch_table
store.db.lockTable=lock_table
4. 创建 TC 数据库表
sql
CREATE DATABASE seata;
USE seata;
-- 全局事务表
CREATE TABLE `global_table` (
`xid` VARCHAR(128) NOT NULL,
`status` TINYINT NOT NULL,
PRIMARY KEY (`xid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- 分支事务表
CREATE TABLE `branch_table` (
`branch_id` BIGINT NOT NULL,
`xid` VARCHAR(128) NOT NULL,
PRIMARY KEY (`branch_id`),
KEY `idx_xid` (`xid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- 锁表
CREATE TABLE `lock_table` (
`row_key` VARCHAR(128) NOT NULL,
`branch_id` BIGINT NOT NULL,
PRIMARY KEY (`row_key`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
5. 启动 Seata Server
bash:
cd /usr/local/seata/bin
./seata-server.sh -h 192.168.61.133 -p 8091
2.4 微服务整合 Seata
1. 依赖引入(所有参与事务的服务)
XML
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-seata</artifactId>
</dependency>
2. 配置文件(application.yml)
yaml:
seata:
registry:
type: nacos
nacos:
server-addr: 192.168.204.129:8848
group: SEATA_GROUP
application: seata-server
tx-service-group: seata-demo
service:
vgroup-mapping:
seata-demo: default
3. 业务改造(事务发起方)
java
@GlobalTransactional // 替换@Transactional,开启全局事务
public void insertOrder(TbOrder tbOrder) {
// 保存订单(本地事务)
tbOrderMapper.insertSelective(tbOrder);
// 远程调用扣减库存(分支事务)
itemServiceFeign.updateItem(tbOrder.getItemId(), tbOrder.getNum());
// 异常时全局回滚
int a = 6 / 0;
}
4. 效果验证
- 异常发生时,订单插入和库存扣减会全局回滚
- 无异常时,所有分支事务正常提交
三、链路追踪 SkyWalking
3.1 为什么需要 SkyWalking
微服务架构下,一个请求可能经过多个服务调用(如:用户下单→订单服务→库存服务→支付服务),传统日志监控无法清晰追踪请求全链路:
- 定位慢查询 / 异常节点困难
- 无法直观看到服务间依赖关系
- 缺乏全链路性能指标分析
3.2 SkyWalking 核心定位
SkyWalking 是国产开源 APM(应用性能管理)工具,由吴晟开源并纳入 Apache 基金会,核心能力:
- 分布式追踪:追踪请求全链路,定位异常节点
- 性能指标分析:监控服务 / 接口响应时间、QPS 等
- 服务依赖分析:可视化展示服务间调用关系
- 告警监控:自定义阈值告警,及时发现问题
3.3 SkyWalking 核心优势
- 低侵入:支持无代码侵入的探针式接入(Agent)
- 多语言支持:Java/Go/Python 等主流语言
- 多数据源适配:支持监控 Elasticsearch/MySQL 等中间件
- 云原生友好:适配 Docker/K8s 等容器化环境
四、实操总结
- 分布式事务:Seata 通过 TC/TM/RM 架构,以 AT 模式实现无侵入的分布式事务管控,解决微服务跨服务 / 跨库的数据一致性问题。
- 链路追踪:SkyWalking 弥补了微服务架构下全链路监控的空白,是定位性能瓶颈、排查分布式问题的核心工具。
- 技术选型建议 :
- 金融级强一致性场景:Seata XA 模式
- 通用业务场景:Seata AT 模式
- 微服务全链路监控:SkyWalking + Prometheus + Grafana
通过 Seata 解决分布式事务一致性问题,结合 SkyWalking 实现全链路可观测,可有效保障微服务架构的稳定性与可维护性。