DukeDuke
主页
项目文档
技术文档
  • 单机版
  • 微服务
  • 代办项目
  • 优鲜项目
项目管理
关于我们
主页
项目文档
技术文档
  • 单机版
  • 微服务
  • 代办项目
  • 优鲜项目
项目管理
关于我们
  • 技术文档

    • 网络原理

      • 交换机
      • 路由器
      • TCP/IP协议
      • HTTP 与 HTTPS
    • 软件架构

      • 什么是软件架构
      • 分层架构
      • 微服务架构
      • 事件驱动架构
      • 领域驱动设计(DDD)
      • 架构图
      • 高并发系统
    • Vue3

      • Vue3简介
      • Vue3响应式系统
      • Vue3组合式API
      • Vue3生命周期
      • Vue3模板语法
      • Vue3组件系统
      • Vue3 路由系统
      • Vue3 状态管理
      • Vue3 性能优化
      • Vue3 TypeScript 支持
      • Vue3 项目实战
      • VUE 面试题大全
      • Node.js 安装
    • JAVA

      • JVM

        • 认识JVM
        • JVM类加载器
        • 运行时数据区
        • 执行引擎
        • 本地方法接口
        • 本地方法库
        • JVM垃圾回收
        • JVM性能监控
        • JVM调优
      • 设计模式
        • 单例模式
        • 工厂模式
        • 策略模式
        • 适配器模式
        • 建造者模式
        • 原型模式
        • 装饰器模式
        • 代理模式
        • 外观模式
        • 享元模式
        • 组合模式
        • 桥接模式
      • Java多线程

        • Java 线程基础详解
        • Java 线程池详解
        • Java ThreadLocal 详解
        • Java volatile 详解
        • Java 线程间通信详解
        • Java 线程安全详解
        • Java 线程调度详解
        • Java 线程优先级详解

        • Java 线程中断详解
        • Java 线程死锁详解
      • Java反射
      • Java 面试题

        • Java 基础概念面试题
        • Java 面向对象编程面试题
        • Java 集合框架面试题
        • Java 多线程与并发面试题
        • JVM 与内存管理面试题
        • Java I/O 与 NIO 面试题
        • Java 异常处理面试题
        • Java 反射与注解面试题
        • Java Spring 框架面试题
        • Java 数据库与 JDBC 面试题
        • Java 性能优化面试题
        • Java 实际项目经验面试题
        • Java 高级特性面试题
        • Java 面试准备建议
    • Python

      • Python简介
      • Python安装
      • Python hello world
      • Python基础语法
      • Python数据类型
      • Python数字
      • Python字符串
      • Python列表
      • Python元组
      • Python字典
      • Python日期时间
      • Python文件操作
      • Python异常处理
      • Python函数
      • Python类
      • Python模块
      • Python包
      • Python多线程
      • Python面向对象
      • Python爬虫
      • Django web框架
      • Python 面试题

        • Python 面试题导航
        • Python 基础概念
        • Python 面向对象编程
        • Python 数据结构
        • Python 高级特性
        • Python 框架
        • Python 性能优化
        • Python 项目经验
    • Spring

      • Spring
      • Springboot
      • Spring Security 安全框架
      • SpringBoot 中的事件详解
      • SpringBoot 中的定时任务详解
      • SpringBoot 自动装配原理与源码解释
    • Mybatis

      • Mybatis
      • Mybatis-Plus
    • 数据库

      • Redis

        • Redis简介
        • Redis(单机)安装
        • Redis配置
        • Redis数据结构
        • RDB、AOF 和混合持久化机制
        • Redis内存管理
        • Redis缓存一致性
        • Redis缓存穿透
        • Redis缓存击穿
        • Redis缓存雪崩
        • Redis Lua脚本
        • Redis主从复制
        • Redis哨兵模式
        • Redis集群
        • Redis数据分片
        • Redis CPU使用率过高
        • Redis面试题
      • MySQL

        • MySQL简介
        • MySQL安装
        • MySQL配置
        • MYSQL日常维护
        • MYSQL优化-慢查询
        • MYSQL优化-索引
        • MYSQL数据库设计规范
    • 消息队列

      • RocketMQ
      • Kafka
      • RabbitMQ
      • 消息队列面试题
    • 微服务

      • SpringCloud 微服务
      • Eureka 注册中心
      • Nacos 注册中心
      • Gateway 网关
      • Feign 服务调用
      • Sentinel 限流 与 熔断
      • Seata 分布式事务
      • CAP 理论
      • Redis 分布式锁
      • 高并发系统设计
    • ELK日志分析系统

      • Elasticsearch 搜索引擎
      • Logstash 数据处理
      • Kibana 可视化
      • ELK 实战
    • 开放API

      • 开放API设计
      • 开放API示例项目
    • 人工智能

      • 人工智能简介
      • 机器学习

      • 深度学习

      • 自然语言处理

      • 计算机视觉

        • CUDA与cuDNN详细安装
        • Conda 安装
        • Pytorch 深度学习框架
        • yolo 目标检测
        • TensorRT 深度学习推理优化引擎
        • TensorFlow 机器学习
        • CVAT 图像标注
        • Windows 下安装 CUDA、cuDNN、TensorRT、TensorRT-YOLO 环境
        • Windows10+CUDA+cuDNN+TensorRT+TensorRT-YOLO 部署高性能YOLO11推理
    • 大数据

      • 大数据简介
      • Hadoop 数据存储
      • Flume 数据采集
      • Sqoop 数据导入导出
      • Hive 数据仓库
      • Spark 数据处理
      • Flink 数据处理
      • Kafka 数据采集
      • HBase 数据存储
      • Elasticsearch 搜索引擎
    • 图像处理

      • 图像处理简介
      • 医学图像web呈现
      • 医学图像处理
      • 切片细胞分离问题
    • 服务器&运维

      • Linux 系统

        • Linux 系统管理
        • Linux 网络管理
        • Linux 文件管理
        • Linux 命令大全
      • Nginx Web 服务器

        • Nginx 安装 与 配置
        • Nginx 负载均衡
        • Nginx SSL证书配置
        • Nginx Keepalived 高可用
      • Docker 容器

        • Docker 简介
        • Docker 安装与配置
        • Docker 命令
        • Docker 部署 Nginx
        • Docker 部署 MySQL
        • Docker 部署 Redis
      • 服务器

        • 塔式服务器
        • 机架式服务器
        • 刀片服务器
      • Git 版本控制
      • Jenkins 持续集成
      • Jmeter 性能测试
      • Let's Encrypt 免费SSL证书
    • 简历

      • 项目经理简历
      • 开发工程师简历

Seata 分布式事务解决方案

概述

Seata(Simple Extensible Autonomous Transaction Architecture)是阿里巴巴开源的分布式事务解决方案,致力于提供高性能和简单易用的分布式事务服务。Seata 为微服务架构提供了高性能、易用的分布式事务解决方案。

核心特性

  • 高性能:基于 AT 模式,对业务无侵入,性能损耗小
  • 易用性:提供多种事务模式,支持多种数据库
  • 高可用:支持集群部署,具备高可用性
  • 强一致性:保证分布式事务的 ACID 特性

分布式事务原理

什么是分布式事务

分布式事务是指事务的参与者、支持事务的服务器、资源服务器以及事务管理器分别位于不同的分布式系统的不同节点之上。

在分布式系统中,一个业务操作往往需要跨越多个服务,每个服务都有自己的数据库。当用户发起一个请求时,可能会同时涉及多个数据库的操作,这些操作要么全部成功,要么全部失败,这就是分布式事务的核心问题。

上图展示了分布式事务的基本架构。用户的一个请求被分发到多个服务(服务 A、服务 B、服务 C),每个服务都操作自己的数据库。这种架构虽然提高了系统的可扩展性和性能,但也带来了数据一致性的挑战。Seata 正是为了解决这种跨服务、跨数据库的事务一致性问题而设计的。

分布式事务的挑战

  1. 网络通信问题:网络延迟、丢包、超时等
  2. 数据一致性问题:多个数据库之间的数据一致性
  3. 性能问题:分布式事务会增加系统复杂度,影响性能
  4. 故障恢复问题:部分节点故障时的数据恢复

Seata 核心架构

整体架构

Seata 采用 TC(Transaction Coordinator)、TM(Transaction Manager)和 RM(Resource Manager)三个核心组件来管理分布式事务。

Seata 的架构设计采用了分层的思想,将整个分布式事务系统分为三个层次。应用层包含 TM 和 RM 两个组件,它们分别负责事务管理和资源管理。协调层只有一个 TC 组件,它是整个系统的核心,负责协调所有的事务操作。数据层包含多个数据库,每个数据库都可能被不同的服务使用。这种分层设计使得系统职责清晰,便于维护和扩展。

核心组件详解

1. TC (Transaction Coordinator) - 事务协调器

TC 是 Seata 的核心组件,负责维护全局事务的运行状态,驱动全局事务的提交或回滚。

主要职责:

  • 维护全局事务状态
  • 协调分支事务的提交或回滚
  • 管理全局锁
  • 处理事务超时

TC 作为事务协调器,承担着整个分布式事务系统的核心职责。它不仅要维护全局事务的状态信息,还要协调各个分支事务的执行。当发生冲突时,TC 需要做出正确的决策,确保数据的一致性。同时,TC 还负责管理全局锁,防止并发事务之间的冲突,并处理事务超时的情况,确保系统的稳定性。

2. TM (Transaction Manager) - 事务管理器

TM 定义了全局事务的边界,负责开启一个全局事务,并最终发起全局提交或全局回滚的决议。

主要职责:

  • 开启全局事务
  • 提交或回滚全局事务
  • 管理事务边界

TM 是分布式事务的发起者和管理者。它负责定义事务的边界,即确定哪些操作属于同一个事务。当业务开始执行时,TM 会开启一个全局事务并生成全局事务 ID。在整个事务执行过程中,TM 会监控事务的执行状态,最终决定是提交还是回滚整个事务。这种设计使得业务代码可以专注于业务逻辑,而不需要关心复杂的事务管理细节。

3. RM (Resource Manager) - 资源管理器

RM 管理分支事务处理的资源,与 TC 交谈以注册分支事务和报告分支事务的状态,并驱动分支事务提交或回滚。

主要职责:

  • 注册分支事务
  • 报告分支事务状态
  • 驱动分支事务提交或回滚
  • 管理本地事务

RM 是分布式事务的执行者,它直接与数据库交互,执行具体的业务操作。每个参与分布式事务的服务都会有一个 RM 实例,负责管理该服务的本地事务。RM 会向 TC 注册分支事务,报告事务的执行状态,并根据 TC 的指令执行提交或回滚操作。这种设计使得每个服务都能独立管理自己的事务,同时又能与全局事务协调一致。

Seata 事务模式

AT 模式(自动事务模式)

AT 模式是 Seata 最常用的模式,对业务无侵入,通过代理数据源实现自动事务管理。

AT 模式原理

AT 模式采用了二阶段提交的思想,但进行了优化以适应分布式环境。在第一阶段,系统会解析业务 SQL,生成前镜像和后镜像,并创建回滚日志。这些操作对业务代码完全透明,业务只需要正常执行 SQL 即可。在第二阶段,根据 TC 的决策,要么删除回滚日志完成提交,要么根据回滚日志执行反向操作完成回滚。这种设计既保证了数据一致性,又对业务代码无侵入。

AT 模式执行流程

  1. 解析阶段:解析业务 SQL,得到 SQL 类型、表名、条件等
  2. 前镜像查询:根据解析结果查询前镜像数据
  3. 执行业务 SQL:执行业务 SQL
  4. 后镜像查询:查询后镜像数据
  5. 生成回滚日志:根据前后镜像生成回滚日志
  6. 注册分支事务:向 TC 注册分支事务

这个时序图详细展示了 AT 模式的完整执行流程。从全局事务的开启到分支事务的注册,再到最终的提交或回滚,每个步骤都有明确的职责分工。TM 负责事务的边界管理,TC 负责全局协调,RM 负责具体的执行操作,DB 负责数据存储。这种分工使得系统既保持了良好的解耦,又能保证事务的一致性。

TCC 模式(Try-Confirm-Cancel)

TCC 模式是一种补偿型事务模式,通过 Try、Confirm、Cancel 三个阶段实现分布式事务。

TCC 模式原理

TCC 模式是一种基于补偿的分布式事务解决方案。在 Try 阶段,系统会进行资源预留和业务检查,确保后续操作能够正常执行。在 Confirm 阶段,系统确认执行业务操作,释放预留的资源,完成事务提交。在 Cancel 阶段,系统取消执行业务操作,释放预留的资源,完成事务回滚。这种设计使得系统能够在出现异常时进行有效的补偿,保证数据的一致性。

TCC 模式示例

以转账业务为例:

这个转账示例清晰地展示了 TCC 模式的工作原理。在 Try 阶段,账户 A 冻结 100 元,账户 B 预留 100 元,确保有足够的资金进行转账。在 Confirm 阶段,账户 A 扣减 100 元,账户 B 增加 100 元,完成实际的转账操作。在 Cancel 阶段,如果出现异常,账户 A 解冻 100 元,账户 B 取消预留,恢复到转账前的状态。这种设计确保了转账操作的原子性和一致性。

SAGA 模式

SAGA 模式是一种长事务解决方案,将一个长事务拆分为多个本地事务,每个本地事务都有对应的补偿操作。

SAGA 模式原理

SAGA 模式特别适用于长事务场景,比如订单处理、支付流程等。它将一个复杂的长事务拆分为多个简单的本地事务,每个本地事务都有对应的补偿操作。当某个事务失败时,系统会按照相反的顺序执行补偿操作,恢复到事务开始前的状态。这种设计使得系统能够处理复杂的业务流程,同时保证数据的一致性。

全局锁机制

全局锁的作用

全局锁用于解决分布式事务中的写隔离问题,防止脏写。

全局锁是 Seata 保证数据一致性的重要机制。在分布式环境中,多个事务可能同时操作同一行数据,如果没有全局锁的保护,就会出现脏写问题。全局锁机制确保同一时间只有一个事务能够修改特定的数据行,其他事务必须等待或者回滚。这种设计虽然会降低并发性能,但能够有效保证数据的一致性。

全局锁实现原理

这个时序图展示了全局锁的申请和分配过程。当事务 A 申请全局锁时,TC 会检查数据库中该行的锁状态。如果锁可用,TC 会授予锁给事务 A。当事务 B 也申请同一个锁时,由于锁已被事务 A 占用,TC 会拒绝事务 B 的申请,事务 B 可以选择等待或者回滚。这种机制确保了同一时间只有一个事务能够修改特定的数据。

事务隔离级别

读未提交(Read Uncommitted)

读未提交是最低的事务隔离级别,允许一个事务读取另一个事务未提交的数据。这种隔离级别虽然性能最好,但会出现脏读、不可重复读和幻读问题。在实际应用中,很少使用这种隔离级别,因为它不能保证数据的一致性。

读已提交(Read Committed)

读已提交隔离级别只允许事务读取已经提交的数据。这种隔离级别可以避免脏读问题,但可能出现不可重复读和幻读问题。读已提交是大多数数据库的默认隔离级别,在性能和一致性之间取得了较好的平衡。

可重复读(Repeatable Read)

可重复读隔离级别确保在一个事务内,多次读取同一数据会得到相同的结果。这种隔离级别通过快照机制实现,可以避免脏读和不可重复读问题,但可能出现幻读问题。可重复读是 Seata 推荐使用的隔离级别,因为它能够很好地平衡性能和一致性。

性能优化策略

1. 异步化处理

异步化处理是提高系统性能的重要手段。对于非关键路径的操作,可以采用异步处理的方式,让用户立即得到响应,然后在后台处理具体的业务逻辑。这种方式可以显著提高系统的响应速度,提升用户体验。在 Seata 中,一些非关键的事务操作可以采用异步方式处理,减少对主流程的影响。

2. 批量处理

批量处理是提高数据库操作效率的有效方法。通过将多个小的操作合并成一个大的批量操作,可以减少网络开销和数据库连接次数,显著提高系统性能。在 Seata 中,可以将多个分支事务的注册、提交等操作进行批量处理,减少与 TC 的通信次数。

3. 连接池优化

连接池是数据库连接管理的重要组件,合理的连接池配置可以显著提高系统性能。最小连接数确保系统有基本的连接可用,最大连接数控制系统的并发能力,连接超时避免长时间等待,空闲超时及时释放不需要的连接。在 Seata 中,合理配置连接池参数可以避免连接不足或连接过多的问题。

高可用部署

集群部署架构

高可用部署是保证系统稳定性的重要手段。通过负载均衡器分发请求,多个应用服务处理业务逻辑,TC 集群协调事务,数据库集群存储数据,整个系统具备了良好的可扩展性和容错能力。当某个节点出现故障时,其他节点可以接管其工作,保证服务的连续性。

故障恢复机制

故障恢复机制是保证系统高可用的关键。系统通过健康检查监控各个节点的状态,当检测到节点故障时,会立即隔离故障节点,重新分配服务,恢复数据,最终使服务恢复正常。这种自动化的故障恢复机制可以最大程度地减少故障对业务的影响。

监控与运维

监控指标

完善的监控体系是保证系统稳定运行的基础。性能指标反映系统的处理能力,业务指标反映事务的执行情况,系统指标反映硬件资源的使用情况。通过监控这些指标,可以及时发现系统问题,进行优化和调整。

日志管理

日志管理是系统运维的重要组成部分。通过收集、存储、分析各种日志,可以了解系统的运行状态,诊断问题,优化性能。当出现异常时,系统会及时发送告警通知,帮助运维人员快速响应和处理问题。

SpringBoot 集成 Seata

环境准备

在开始集成 Seata 之前,需要准备以下环境:

  1. Java 8+
  2. SpringBoot 2.1+
  3. MySQL 5.7+
  4. Seata Server 1.4+

1. 添加依赖

在 pom.xml 中添加 Seata 相关依赖:

<dependencies>
    <!-- SpringBoot Web Starter -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>

    <!-- SpringBoot Data JPA -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-jpa</artifactId>
    </dependency>

    <!-- MySQL 驱动 -->
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <scope>runtime</scope>
    </dependency>

    <!-- Seata SpringBoot Starter -->
    <dependency>
        <groupId>io.seata</groupId>
        <artifactId>seata-spring-boot-starter</artifactId>
        <version>1.4.2</version>
    </dependency>

    <!-- Seata 数据源代理 -->
    <dependency>
        <groupId>io.seata</groupId>
        <artifactId>seata-datasource-proxy</artifactId>
        <version>1.4.2</version>
    </dependency>

    <!-- Nacos 配置中心(可选) -->
    <dependency>
        <groupId>com.alibaba.nacos</groupId>
        <artifactId>nacos-client</artifactId>
        <version>1.4.1</version>
    </dependency>
</dependencies>

2. 配置文件

application.yml 配置

server:
  port: 8080

spring:
  application:
    name: seata-demo
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/seata_demo?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai
    username: root
    password: 123456
    # 使用 Seata 数据源代理
    type: com.alibaba.druid.pool.DruidDataSource
    druid:
      initial-size: 5
      min-idle: 5
      max-active: 20
      max-wait: 60000
      time-between-eviction-runs-millis: 60000
      min-evictable-idle-time-millis: 300000
      validation-query: SELECT 1 FROM DUAL
      test-while-idle: true
      test-on-borrow: false
      test-on-return: false
      pool-prepared-statements: true
      max-pool-prepared-statement-per-connection-size: 20
      filters: stat,wall,log4j2
      connection-properties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000

  jpa:
    hibernate:
      ddl-auto: update
    show-sql: true
    properties:
      hibernate:
        dialect: org.hibernate.dialect.MySQL8Dialect

# Seata 配置
seata:
  enabled: true
  application-id: ${spring.application.name}
  tx-service-group: my_test_tx_group
  service:
    vgroup-mapping:
      my_test_tx_group: default
    grouplist:
      default: 127.0.0.1:8091
  config:
    type: file
    file:
      name: file.conf
  registry:
    type: file
    file:
      name: file.conf
  client:
    rm:
      async-commit-buffer-limit: 10000
      report-retry-count: 5
      table-meta-check-enable: false
      report-success-enable: false
      saga-branch-register-enable: false
      saga-json-parser: fastjson
      saga-retry-persist-mode-update: false
      saga-compensate-persist-mode-update: false
    tm:
      commit-retry-count: 5
      rollback-retry-count: 5
      default-global-transaction-timeout: 60000
      degrade-check: false
      degrade-check-allow-times: 10
      degrade-check-period: 2000
    undo:
      data-validation: true
      only-care-update-columns: true
      log-serialization: jackson
      log-table: undo_log
    log:
      exceptionRate: 100

# 日志配置
logging:
  level:
    io.seata: debug
    com.alibaba.druid: debug

file.conf 配置

在 resources 目录下创建 file.conf 文件:

transport {
  # tcp udt unix-domain-socket
  type = "TCP"
  #NIO NATIVE
  server = "NIO"
  #enable heartbeat
  heartbeat = true
  #thread factory for netty
  thread-factory {
    boss-thread-prefix = "NettyBoss"
    worker-thread-prefix = "NettyServerNIOWorker"
    server-executor-thread-prefix = "NettyServerBizHandler"
    share-boss-worker = false
    client-selector-thread-prefix = "NettyClientSelector"
    client-selector-thread-size = 1
    client-worker-thread-prefix = "NettyClientWorkerThread"
    # netty boss thread size,will not be used for UDT
    boss-thread-size = 1
    #auto default pin or 8
    worker-thread-size = 8
  }
  shutdown {
    # when destroy server, wait seconds
    wait = 3
  }
  serialization = "seata"
  compressor = "none"
}

service {
  #transaction service group mapping
  vgroupMapping.my_test_tx_group = "default"
  #only support when registry.type=file, please don't set multiple addresses
  default.grouplist = "127.0.0.1:8091"
  #degrade, current not support
  enableDegrade = false
  #disable seata
  disableGlobalTransaction = false
}

client {
  rm {
    asyncCommitBufferLimit = 10000
    reportRetryCount = 5
    tableMetaCheckEnable = false
    reportSuccessEnable = false
    sagaBranchRegisterEnable = false
    sagaJsonParser = "fastjson"
    sagaRetryPersistModeUpdate = false
    sagaCompensatePersistModeUpdate = false
  }
  tm {
    commitRetryCount = 5
    rollbackRetryCount = 5
    defaultGlobalTransactionTimeout = 60000
    degradeCheck = false
    degradeCheckAllowTimes = 10
    degradeCheckPeriod = 2000
  }
  undo {
    dataValidation = true
    onlyCareUpdateColumns = true
    logSerialization = "jackson"
    logTable = "undo_log"
  }
  log {
    exceptionRate = 100
  }
}

3. 数据源配置

创建数据源配置类:

@Configuration
public class DataSourceConfig {

    @Bean
    @ConfigurationProperties("spring.datasource.druid")
    public DruidDataSource druidDataSource() {
        return new DruidDataSource();
    }

    @Bean
    public DataSource dataSource(DruidDataSource druidDataSource) {
        return new DataSourceProxy(druidDataSource);
    }

    @Bean
    public PlatformTransactionManager transactionManager(DataSource dataSource) {
        return new DataSourceTransactionManager(dataSource);
    }
}

4. 业务代码示例

实体类

@Entity
@Table(name = "account")
public class Account {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column(name = "user_id")
    private String userId;

    @Column(name = "money")
    private BigDecimal money;

    // getter and setter methods
    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getUserId() {
        return userId;
    }

    public void setUserId(String userId) {
        this.userId = userId;
    }

    public BigDecimal getMoney() {
        return money;
    }

    public void setMoney(BigDecimal money) {
        this.money = money;
    }
}

Repository 接口

@Repository
public interface AccountRepository extends JpaRepository<Account, Long> {

    @Modifying
    @Query("UPDATE Account a SET a.money = a.money - :amount WHERE a.userId = :userId")
    int debit(@Param("userId") String userId, @Param("amount") BigDecimal amount);

    @Modifying
    @Query("UPDATE Account a SET a.money = a.money + :amount WHERE a.userId = :userId")
    int credit(@Param("userId") String userId, @Param("amount") BigDecimal amount);

    Optional<Account> findByUserId(String userId);
}

业务服务类

@Service
public class AccountService {

    @Autowired
    private AccountRepository accountRepository;

    /**
     * 扣减账户余额
     * @param userId 用户ID
     * @param money 扣减金额
     * @return 操作结果
     */
    @GlobalTransactional(rollbackFor = Exception.class)
    public boolean debit(String userId, BigDecimal money) {
        Account account = accountRepository.findByUserId(userId)
            .orElseThrow(() -> new RuntimeException("账户不存在"));

        if (account.getMoney().compareTo(money) < 0) {
            throw new RuntimeException("账户余额不足");
        }

        int result = accountRepository.debit(userId, money);
        if (result <= 0) {
            throw new RuntimeException("扣减失败");
        }

        return true;
    }

    /**
     * 增加账户余额
     * @param userId 用户ID
     * @param money 增加金额
     * @return 操作结果
     */
    @GlobalTransactional(rollbackFor = Exception.class)
    public boolean credit(String userId, BigDecimal money) {
        int result = accountRepository.credit(userId, money);
        if (result <= 0) {
            throw new RuntimeException("增加失败");
        }

        return true;
    }

    /**
     * 转账操作
     * @param fromUserId 转出用户ID
     * @param toUserId 转入用户ID
     * @param money 转账金额
     * @return 操作结果
     */
    @GlobalTransactional(rollbackFor = Exception.class)
    public boolean transfer(String fromUserId, String toUserId, BigDecimal money) {
        // 扣减转出账户
        debit(fromUserId, money);

        // 增加转入账户
        credit(toUserId, money);

        return true;
    }
}

控制器

@RestController
@RequestMapping("/api/account")
public class AccountController {

    @Autowired
    private AccountService accountService;

    /**
     * 转账接口
     */
    @PostMapping("/transfer")
    public ResponseEntity<String> transfer(@RequestParam String fromUserId,
                                         @RequestParam String toUserId,
                                         @RequestParam BigDecimal money) {
        try {
            boolean result = accountService.transfer(fromUserId, toUserId, money);
            if (result) {
                return ResponseEntity.ok("转账成功");
            } else {
                return ResponseEntity.badRequest().body("转账失败");
            }
        } catch (Exception e) {
            return ResponseEntity.badRequest().body("转账失败: " + e.getMessage());
        }
    }

    /**
     * 查询账户余额
     */
    @GetMapping("/balance/{userId}")
    public ResponseEntity<BigDecimal> getBalance(@PathVariable String userId) {
        try {
            Account account = accountService.findByUserId(userId);
            return ResponseEntity.ok(account.getMoney());
        } catch (Exception e) {
            return ResponseEntity.badRequest().body(BigDecimal.ZERO);
        }
    }
}

5. 数据库初始化

创建数据库表:

-- 账户表
CREATE TABLE `account` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `user_id` varchar(50) NOT NULL,
  `money` decimal(10,2) NOT NULL DEFAULT '0.00',
  PRIMARY KEY (`id`),
  UNIQUE KEY `uk_user_id` (`user_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

-- Seata 回滚日志表
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=utf8mb4;

-- 初始化测试数据
INSERT INTO `account` (`user_id`, `money`) VALUES
('user001', 1000.00),
('user002', 1000.00);

6. 启动类

@SpringBootApplication
@EnableTransactionManagement
public class SeataDemoApplication {

    public static void main(String[] args) {
        SpringApplication.run(SeataDemoApplication.class, args);
    }
}

7. 测试验证

正常转账测试

# 转账 100 元从 user001 到 user002
curl -X POST "http://localhost:8080/api/account/transfer?fromUserId=user001&toUserId=user002&money=100"

# 查询 user001 余额
curl "http://localhost:8080/api/account/balance/user001"

# 查询 user002 余额
curl "http://localhost:8080/api/account/balance/user002"

异常回滚测试

修改 AccountService 中的 transfer 方法,添加异常:

@GlobalTransactional(rollbackFor = Exception.class)
public boolean transfer(String fromUserId, String toUserId, BigDecimal money) {
    // 扣减转出账户
    debit(fromUserId, money);

    // 增加转入账户
    credit(toUserId, money);

    // 模拟异常,触发回滚
    if (money.compareTo(new BigDecimal("500")) > 0) {
        throw new RuntimeException("转账金额过大,触发回滚");
    }

    return true;
}

测试大额转账,验证事务回滚:

# 转账 600 元(会触发异常和回滚)
curl -X POST "http://localhost:8080/api/account/transfer?fromUserId=user001&toUserId=user002&money=600"

8. 多服务分布式事务示例

订单服务

@Service
public class OrderService {

    @Autowired
    private OrderRepository orderRepository;

    @GlobalTransactional(rollbackFor = Exception.class)
    public boolean createOrder(String userId, BigDecimal amount) {
        Order order = new Order();
        order.setUserId(userId);
        order.setAmount(amount);
        order.setStatus("PENDING");
        order.setCreateTime(new Date());

        orderRepository.save(order);

        // 调用库存服务扣减库存
        inventoryService.decreaseStock(order.getProductId(), order.getQuantity());

        // 调用账户服务扣减余额
        accountService.debit(userId, amount);

        // 更新订单状态
        order.setStatus("COMPLETED");
        orderRepository.save(order);

        return true;
    }
}

库存服务

@Service
public class InventoryService {

    @Autowired
    private InventoryRepository inventoryRepository;

    @GlobalTransactional(rollbackFor = Exception.class)
    public boolean decreaseStock(String productId, Integer quantity) {
        Inventory inventory = inventoryRepository.findByProductId(productId)
            .orElseThrow(() -> new RuntimeException("商品不存在"));

        if (inventory.getStock() < quantity) {
            throw new RuntimeException("库存不足");
        }

        inventory.setStock(inventory.getStock() - quantity);
        inventoryRepository.save(inventory);

        return true;
    }
}

9. 配置优化建议

性能优化配置

seata:
  client:
    rm:
      # 异步提交缓冲区限制
      async-commit-buffer-limit: 10000
      # 报告重试次数
      report-retry-count: 5
      # 禁用表元数据检查
      table-meta-check-enable: false
    tm:
      # 提交重试次数
      commit-retry-count: 5
      # 回滚重试次数
      rollback-retry-count: 5
      # 默认全局事务超时时间(毫秒)
      default-global-transaction-timeout: 60000
    undo:
      # 数据验证
      data-validation: true
      # 只关心更新的列
      only-care-update-columns: true
      # 日志序列化方式
      log-serialization: jackson

高可用配置

seata:
  service:
    vgroup-mapping:
      my_test_tx_group: default
    grouplist:
      default: 127.0.0.1:8091,127.0.0.1:8092,127.0.0.1:8093
  registry:
    type: nacos
    nacos:
      application: seata-server
      server-addr: 127.0.0.1:8848
      group: SEATA_GROUP
      namespace: seata
      cluster: default

最佳实践

1. 事务设计原则

  • 事务粒度控制:避免大事务,合理拆分
  • 超时设置:设置合理的超时时间
  • 重试机制:实现幂等性,支持重试
  • 监控告警:建立完善的监控体系

2. 性能优化建议

  • 异步处理:非关键路径使用异步处理
  • 批量操作:合理使用批量操作提高性能
  • 连接池优化:合理配置连接池参数
  • 缓存策略:使用缓存减少数据库访问

3. 故障处理策略

  • 快速失败:设置合理的超时时间
  • 降级策略:实现服务降级机制
  • 熔断机制:防止雪崩效应
  • 数据备份:定期备份重要数据

4. SpringBoot 集成最佳实践

  • 配置管理:使用配置中心统一管理配置
  • 服务发现:集成注册中心实现服务发现
  • 监控集成:集成 Micrometer 进行指标监控
  • 日志管理:使用 SLF4J + Logback 进行日志管理
  • 健康检查:实现健康检查端点
  • 优雅关闭:配置优雅关闭参数

总结

Seata 作为阿里巴巴开源的分布式事务解决方案,提供了完整的分布式事务管理能力。通过 AT、TCC、SAGA 等多种事务模式,可以满足不同业务场景的需求。其核心组件 TC、TM、RM 协同工作,保证了分布式事务的 ACID 特性。

在实际应用中,需要根据业务特点选择合适的事务模式,并注意性能优化和故障处理,确保系统的稳定性和可靠性。

最近更新:: 2025/9/11 08:55
Contributors: Duke
Prev
Sentinel 限流 与 熔断
Next
CAP 理论