如何在 Spring Boot 中集成 Seata,解决分布式事务?

云计算 分布式
本文将详细介绍如何在 Spring Boot 项目中集成 Seata,并通过具体的代码案例实现分布式事务管理。以下内容包括配置、代码实现以及一些注意事项,帮助你快速上手。

在分布式系统中,服务之间往往涉及多个数据库操作,这就需要一个可靠的分布式事务解决方案来确保数据的一致性。Seata(Simple Extensible Autonomous Transaction Architecture)是一个开源的分布式事务解决方案,提供了高性能和易用的分布式事务服务。

本文将详细介绍如何在 Spring Boot 项目中集成 Seata,并通过具体的代码案例实现分布式事务管理。以下内容包括配置、代码实现以及一些注意事项,帮助你快速上手。

整体步骤

1、准备工作:

  • 搭建 Seata Server 环境
  • 创建两个模拟服务 order-service 和 account-service,分别代表订单和账户的服务
  • 准备一个 Eureka/Nacos 注册中心(推荐 Nacos)

2、配置 Seata:

  • 在项目中引入 Seata 依赖
  • 配置 Seata 客户端
  • 配置数据源代理

3、代码实现:

  • 使用 @GlobalTransactional 注解实现全局事务管理
  • 编写业务逻辑和分布式事务示例

环境搭建

1、下载并启动 Seata Server

从 Seata 官方仓库下载 Seata Server:https://github.com/seata/seata/releases。解压后,修改 conf/registry.conf 文件,将注册中心改为 Nacos:

registry {
  type = "nacos"

  nacos {
    serverAddr = "localhost:8848"  # Nacos 服务地址
    namespace = ""                 # Nacos 命名空间
    cluster = "default"
  }
}

config {
  type = "nacos"

  nacos {
    serverAddr = "localhost:8848"
    namespace = ""
    group = "SEATA_GROUP"
  }
}

启动 Seata Server:

sh bin/seata-server.sh

依赖引入

在两个 Spring Boot 项目中添加以下依赖:

<dependency>
    <groupId>io.seata</groupId>
    <artifactId>seata-spring-boot-starter</artifactId>
    <version>1.6.1</version>
</dependency>
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
    <version>2021.0.4.0</version>
</dependency>
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
    <version>2021.0.4.0</version>
</dependency>

配置文件详解

以下是 application.yml 配置文件示例(order-service 和 account-service 的配置基本相同,区别仅在服务名上)。

order-service 配置

server:
  port: 8081

spring:
  application:
    name: order-service
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/order_db?useUnicode=true&characterEncoding=utf-8&serverTimezone=UTC
    username: root
    password: 123456
    type: com.zaxxer.hikari.HikariDataSource

mybatis-plus:
  mapper-locations: classpath:/mapper/*.xml

seata:
  enabled: true
  tx-service-group: my_tx_group  # 事务组名,与 Seata Server 配置一致

account-service 配置

server:
  port: 8082

spring:
  application:
    name: account-service
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/account_db?useUnicode=true&characterEncoding=utf-8&serverTimezone=UTC
    username: root
    password: 123456
    type: com.zaxxer.hikari.HikariDataSource

mybatis-plus:
  mapper-locations: classpath:/mapper/*.xml

seata:
  enabled: true
  tx-service-group: my_tx_group  # 事务组名

数据库表设计

订单表 order_tbl

CREATE TABLE order_tbl (
  id BIGINT AUTO_INCREMENT PRIMARY KEY,
  user_id VARCHAR(64) NOT NULL,
  product_id VARCHAR(64) NOT NULL,
  count INT NOT NULL,
  money DECIMAL(10,2) NOT NULL,
  status INT DEFAULT 0 COMMENT '0:待支付, 1:已支付'
);

账户表 account_tbl

CREATE TABLE account_tbl (
  id BIGINT AUTO_INCREMENT PRIMARY KEY,
  user_id VARCHAR(64) NOT NULL,
  total DECIMAL(10,2) NOT NULL,
  used DECIMAL(10,2) NOT NULL,
  residue DECIMAL(10,2) NOT NULL
);

核心代码实现

1、全局事务注解

Seata 提供了 @GlobalTransactional 注解,用于在分布式事务中管理多个服务调用。

2、OrderService 示例

OrderService 中模拟订单创建逻辑,同时调用 AccountService 扣减账户余额。

代码实现
@Service
@Slf4j
public class OrderService {

    @Autowired
    private OrderMapper orderMapper;

    @Autowired
    private AccountClient accountClient; // Feign 客户端调用 AccountService

    @GlobalTransactional(name = "create-order-transaction", rollbackFor = Exception.class)
    public void createOrder(String userId, String productId, int count, BigDecimal money) {
        log.info("-----> 开始新建订单");
        Order order = new Order();
        order.setUserId(userId);
        order.setProductId(productId);
        order.setCount(count);
        order.setMoney(money);
        order.setStatus(0);
        orderMapper.insert(order);

        log.info("-----> 订单服务调用账户,开始扣减余额");
        accountClient.decreaseAccount(userId, money);
        log.info("-----> 订单服务调用账户,扣减余额完成");

        log.info("-----> 修改订单状态为已完成");
        order.setStatus(1);
        orderMapper.updateById(order);

        log.info("-----> 订单处理结束");
    }
}
Mapper 层
@Mapper
public interface OrderMapper extends BaseMapper<Order> {}

3、AccountService 示例

AccountService 中实现账户余额的扣减逻辑。

代码实现
@Service
@Slf4j
public class AccountService {

    @Autowired
    private AccountMapper accountMapper;

    public void decreaseAccount(String userId, BigDecimal money) {
        log.info("-----> 扣减账户余额开始");
        accountMapper.decrease(userId, money);
        log.info("-----> 扣减账户余额结束");
    }
}
Mapper 层
@Mapper
public interface AccountMapper {

    @Update("UPDATE account_tbl SET residue = residue - #{money}, used = used + #{money} WHERE user_id = #{userId}")
    void decrease(@Param("userId") String userId, @Param("money") BigDecimal money);
}

4、Feign Client 示例

@FeignClient(name = "account-service")
public interface AccountClient {

    @PostMapping("/account/decrease")
    void decreaseAccount(@RequestParam("userId") String userId, @RequestParam("money") BigDecimal money);
}

测试分布式事务

启动服务后,通过 Postman 或其他工具发送请求:

curl -X POST http://localhost:8081/order/create \
     -H "Content-Type: application/json" \
     -d '{
           "userId": "1",
           "productId": "1",
           "count": 10,
           "money": 100.00
         }'

重要注意事项

1、Seata Undo Log 表: 在每个数据库中创建 undo_log 表,供 Seata 记录回滚日志。

CREATE TABLE undo_log (
    id BIGINT AUTO_INCREMENT PRIMARY KEY,
    branch_id BIGINT NOT NULL,
    xid VARCHAR(128) NOT NULL,
    context VARCHAR(128) NOT NULL,
    rollback_info LONGBLOB NOT NULL,
    log_status INT NOT NULL,
    log_created DATETIME NOT NULL,
    log_modified DATETIME NOT NULL,
    UNIQUE KEY ux_undo_log (xid, branch_id)
);

2、Seata 配置中心: 确保 Seata Server 的配置与服务端一致,事务组名必须统一。

总结

通过以上配置和代码示例,我们实现了基于 Seata 的分布式事务管理。在实际项目中,可以根据业务需求灵活调整服务和表设计,确保数据一致性。

如果需要更深入的优化或其他集成方法,可以进一步研究 Seata 的 AT、TCC 模式以及高可用配置。

责任编辑:武晓燕 来源: 架构师秋天
相关推荐

2022-03-24 07:51:27

seata分布式事务Java

2024-10-09 14:14:07

2022-06-27 08:21:05

Seata分布式事务微服务

2022-06-21 08:27:22

Seata分布式事务

2020-12-09 09:14:57

SpringCloudSeata 分布式

2020-12-08 11:43:03

Spring Clou分布式Seata

2022-07-10 20:24:48

Seata分布式事务

2021-04-23 08:15:51

Seata XA AT

2023-11-06 13:15:32

分布式事务Seata

2022-06-14 10:47:00

分布式事务数据

2024-08-19 09:05:00

Seata分布式事务

2020-04-28 12:18:08

Seata模式分布式

2022-01-12 10:02:02

TCC模式 Seata

2023-01-06 09:19:12

Seata分布式事务

2022-07-03 14:03:57

分布式Seata

2020-05-28 09:35:05

分布式事务方案

2023-08-17 10:23:07

扩展方案

2024-12-02 09:19:44

2022-10-26 17:28:41

分布式事务seata

2024-01-26 08:18:03

点赞
收藏

51CTO技术栈公众号