Seata之分布式事务问题及解决方案

2025-03-14 01:50

本文主要是介绍Seata之分布式事务问题及解决方案,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

《Seata之分布式事务问题及解决方案》:本文主要介绍Seata之分布式事务问题及解决方案,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教...

Seata–分布式事务解决方案

简介

Seata 是阿里开源的分布式事务解决方案,提供 ATXATCCSaga 四种事务模式,支持微服务架构下的数据一致性。

官网:https://seata.apache.org/zh-cn/

同类产品对比

方案核心特点适用场景
Seata多模式支持,代码侵入性低,社区活跃复杂业务场景,需灵活选择模式
阿里云 GTS商业版方案,功能全面,性能强企业级付费场景
RocketMQ 事务消息基于消息队列实现最终一致性异步高吞吐场景
LCN基于代理模式,实现简单轻量级快速接入

环境搭建

1.微服务

创建 Spring Cloud 项目,推荐使用以下组件:

<!-- Spring Cloud Alibaba 依赖 -->
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-seata</artifactId>
</dependency>

2.SQL

每个微服务数据库需创建 undo_log 表(AT模式必需):

-- 每个业务数据库均需执行
CREATE TABLE IF NOT EXISTS `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,
    PRIMARY KEY (`id`),
    UNIQUE KEY `ux_undo_log` (`xid`, `branch_id`)
) ENGINE = InnoDB
  AUTO_INCREMENT = 1
  DEFAULT CHARSET = utf8;

3.seata-server

  • 1.下载 :https://seata.apache.org/zh-cn/download/seata-server
  • 2.解压并启动:seata-server.BAT
  • 3.控制台:http://127.0.0.1:7091/#/transaction/list

4.微服务配置

依赖

除基础依赖外需添加:

<dependency>
  <groupId>com.alibaba.cloud</groupId>
  <artifactId>spring-cloud-starter-alibaba-seata</artifactId>
</dependency>

配置

每个微服务创建 file.conf文件,完整内容如下;

【微服务只需要复制 service 块配置即可】

#
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements.  See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License.  You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#

transport {
  # tcp, Unix-domain-socket
  type = "TCP"
  #NIO, NATIVE
  server = "NIO"
  #enable heartbeat
  heartbeat = true
  # the tm client batch send request enable
  enableTmClientBatchSendRequest = false
  # the rm client batch send request enable
  enableRmClientBatchSendRequest = true
   # the rm client rpc request timeout
  rpcRmRequestTimeout = 2000
  # the tm client rpc request timeout
  rpcTmRequestTimeout = 30000
  # the rm client rpc request timeout
  rpcRmRequestTimeout = 15000
  #thread factory for netty
  threadFactory {
    bossThreadPrefix = "NettyBoss"
    workerThreadPrefix = "NettyServerNIOWorker"
    serverExecutorThread-prefix = "NettyServerBizHandler"
    shareBossWorker = false
    clientSelectorThreadPrefix = "NettyClientSelector"
    clientSelectorThreadSize = 1
    clientWorkerThreadPrefix = "NettyClientWorkerThread"
    # netty boss thread size
    bossThreadSize = 1
    #auto default pin or 8
    workerThreadSize = "default"
  }
  shutdown {
    # when destroy server, wait seconds
    wait = 3
  }
  serialization = "seata"
  compressor = "none"
}
service {
  #transaction service group mapping
  vgroupMapping.default_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
    lock {
      retryInterval = 10
      retryTimes = 30
      retryPolicyBranchRollbackOnConflict = true
    }
    reportRetryCount = 5
    tableMetaCheckEnable = false
    tableMetaCheckerInterval = 60000
    reportSuccessEnable = false
    sagaBranchRegisterEnable = false
    sagajsonParser = "fastjson"
    sagaRetryPersistModeUpdate = false
    phpsagaCompensatePersistModeUpdate = false
    tccActionInterceptorOrder = -2147482648 #Ordered.HIGHEST_PRECEDENCE + 1000
    sqlParserType = "druid"
    branchExecutionTimeoutXA = 60000
    connectionTwoPhaseHoldTimeoutXA = 10000
  }
  tm {
    commitRetryCount = 5
    rollbackRetryCount = 5
    defaultGlobalTransactionTimeout = 60000
    degradeCheck = false
    degradeCheckPeriod = 2000
    degradeCheckAllowTimes = 10
    interceptorOrder = -2147482648 #Ordered.HIGHEST_PRECEDENCE + 1000
  }
  undo {
    dataValidation = true
    onlyCareUpdateColumns = true
    logSerialization = "jackson"
    logTable = "undo_log"
    compress {
      enable = true
      # allow zip, gzip, deflater, lz4, bzip2, zstd default is zip
      type = zip
      # if rollback info size > threshold, then will be compress
      # allow k m g t
      threshold = 64k
    }
  }
  loadBalance {
      type = "XID"
      virtualNodes = 10
  }
}
log {
  exceptionRate = 100
}
tcc {
  fence {
    # tcc fence log table name
    logTableName = tcc_fence_log
    # tcc fence log clean period
    cleanPeriod = 1h
  }
}

事务模式

1.AT模式(推荐:自动补偿)

二阶提交协议原理

原理:基于反向SQL补偿,自动生成回滚日志

Seata之分布式事务问题及解决方案

使用

@Service
public class OrderService {
    @GlobalTransactional(name = "createOrder", timeoutMills = 60000)
    public void createOrder(OrderDTO order) {
        // 1. 扣减库存(调用库存服务)
        storageFeignClient.deduct(order.getProductId());
        // 2. 创建订单(本地事务)
        orderMapper.insert(order);
        // 3. 模拟异常触发回滚
        int i = 1 / 0; 
    }
}

关键机制

  • 一阶段:提交本地事务,生成回滚日志(undo_log)
  • 二阶段:成功则异步删除日志,失败则通过日志反向补偿

特点

  • 对代码无侵入
  • 需创建undo_log表
  • 适用于大多数CRUD场景

2.XA模式(强一致)

原理:基于数据库XA协议的两阶段提交

配置

seata:
  data-source-proxy-mode: XA  # 默认AT

特点:

  • 基于数据库XA协议
  • 两阶段提交(2PC)
  • 事务持有锁时间较长,适合短事务

适用场景:强一致性需求,支持XA协议的数据库(如mysql 5.7+)

3.TCC模式(手动补偿)

原理:Try-Confirm-Cancel 三阶段控制

实现

// 1. 定义TCC接口
public interface StorageTccService {
    @TwoPhaseBusinessAction(name = "deduct", 
                          commitMethod = "confirm", 
                          rollbackMethod = "cancel")
    boolean deduct(@BusinessActionContextParameter(paramName = "productId") String productId,
                   @BusinessActionContextParameter(paramName = "count") Integer count);
 android   
    boolean confirm(BusinessActionContext context);
    boolean cancel(BusinessActionContext context);
}

// 2. 实现Try逻辑
@Service
public class StorageTccServiceImpl implements StorageTccService {
    @Override
    public boolean deduct(String productId, Integer count) {
        // Try阶段:资源预留(例如冻结库存)
        return storageMapper.freezeStock(productId, count) > 0;
    }
    
    @Override
    public boolean confirm(BusinessActionContext context) {
        // Confirm阶段:真实扣减(例如删除冻结记录)
        String productId = context.getActionContext("productId");
  android      Integer count = context.getActionContext("count");
        return storageMapper.reduceStock(productId, count) > 0;
    }
    
    @Override
    public boolean cancel(BusinessActionContext context) {
        // Cancel阶段:释放资源(例如恢复冻结库存)
        String productId = context.getActionContext("productId");
        Integer count = context.getActionContext("count");
        return storageMappandroider.unfreezeStock(productId, count) > 0;
    }
}

使用限制:

  • 需自行实现Try/Confirm/Cancel方法
  • Confirm和Cancel需保证幂等性

特点:高性能,但javascript需手动编写补偿逻辑

4.Saga模式(长事务)

实现方式:

通过状态机配置补偿策略:

@SagaStart
public void createOrderSaga(Order order) {
    // 1. 创建订单
    orderService.create(order);
    // 2. 调用支付服务(若失败则触发逆向操作)
    paymentService.pay(order.getId());
}
// 定义补偿方法
@Compensate
public void compensateOrder(Order order) {
    orderService.delete(order.getId());
}

原理:长事务拆分+逆向补偿

适用场景:跨系统长时间操作(如订单+物流+支付)

总结

模式选型对照表:

模式一致性性能侵入性适用场景
AT弱一致常规业务(库存扣减、订单创建)
TCC强一致资金交易、需精准控制
XA强一致银行转账、短事务
Saga最终一致跨系统长流程(订单+物流+支付)

核心要点:

分类要点说明
选型AT模式适用于大多数场景,TCC适合高性能要求,XA适合强一致性
配置确保seata-server与微服务的registry配置一致
事务ID通过RootContext.getXID()可获取当前事务ID
排错检查undo_log表记录,查看seata-server控制台日志

最佳实践:

  1. 生产环境建议使用Nacos作为配置中心
  2. AT模式需要开启数据库的本地事务支持(如MySQL的InnoDB引擎)
  3. 全局事务超时时间建议设置:seata.tx.timeout=60000(单位毫秒)

以上为个人经验,希望能给大家一个参考,也希望大家多多支持China编程(www.chinasem.cn)。

这篇关于Seata之分布式事务问题及解决方案的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1153736

相关文章

Pyserial设置缓冲区大小失败的问题解决

《Pyserial设置缓冲区大小失败的问题解决》本文主要介绍了Pyserial设置缓冲区大小失败的问题解决,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面... 目录问题描述原因分析解决方案问题描述使用set_buffer_size()设置缓冲区大小后,buf

resultMap如何处理复杂映射问题

《resultMap如何处理复杂映射问题》:本文主要介绍resultMap如何处理复杂映射问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录resultMap复杂映射问题Ⅰ 多对一查询:学生——老师Ⅱ 一对多查询:老师——学生总结resultMap复杂映射问题

jupyter代码块没有运行图标的解决方案

《jupyter代码块没有运行图标的解决方案》:本文主要介绍jupyter代码块没有运行图标的解决方案,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录jupyter代码块没有运行图标的解决1.找到Jupyter notebook的系统配置文件2.这时候一般会搜索到

java实现延迟/超时/定时问题

《java实现延迟/超时/定时问题》:本文主要介绍java实现延迟/超时/定时问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录Java实现延迟/超时/定时java 每间隔5秒执行一次,一共执行5次然后结束scheduleAtFixedRate 和 schedu

如何解决mmcv无法安装或安装之后报错问题

《如何解决mmcv无法安装或安装之后报错问题》:本文主要介绍如何解决mmcv无法安装或安装之后报错问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录mmcv无法安装或安装之后报错问题1.当我们运行YOwww.chinasem.cnLO时遇到2.找到下图所示这里3.

浅谈配置MMCV环境,解决报错,版本不匹配问题

《浅谈配置MMCV环境,解决报错,版本不匹配问题》:本文主要介绍浅谈配置MMCV环境,解决报错,版本不匹配问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录配置MMCV环境,解决报错,版本不匹配错误示例正确示例总结配置MMCV环境,解决报错,版本不匹配在col

Vue3使用router,params传参为空问题

《Vue3使用router,params传参为空问题》:本文主要介绍Vue3使用router,params传参为空问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐... 目录vue3使用China编程router,params传参为空1.使用query方式传参2.使用 Histo

SpringBoot首笔交易慢问题排查与优化方案

《SpringBoot首笔交易慢问题排查与优化方案》在我们的微服务项目中,遇到这样的问题:应用启动后,第一笔交易响应耗时高达4、5秒,而后续请求均能在毫秒级完成,这不仅触发监控告警,也极大影响了用户体... 目录问题背景排查步骤1. 日志分析2. 性能工具定位优化方案:提前预热各种资源1. Flowable

Python FastAPI+Celery+RabbitMQ实现分布式图片水印处理系统

《PythonFastAPI+Celery+RabbitMQ实现分布式图片水印处理系统》这篇文章主要为大家详细介绍了PythonFastAPI如何结合Celery以及RabbitMQ实现简单的分布式... 实现思路FastAPI 服务器Celery 任务队列RabbitMQ 作为消息代理定时任务处理完整

springboot循环依赖问题案例代码及解决办法

《springboot循环依赖问题案例代码及解决办法》在SpringBoot中,如果两个或多个Bean之间存在循环依赖(即BeanA依赖BeanB,而BeanB又依赖BeanA),会导致Spring的... 目录1. 什么是循环依赖?2. 循环依赖的场景案例3. 解决循环依赖的常见方法方法 1:使用 @La