【Seata】SpringCloud集成Seatav1.6之XA模式

目录

开始语

简介

1.描述

2.工作机制

3.简单总结分析

代码演示

1.配置数据源

2.application.yml和nacos服务中的配置

3.orders服务的service实现代码

4.stock服务的service实现代码

结果分析

1.业务执行成功

2.业务执行失败

XA模式的优缺点

适用场景

本项目代码地址

结束语


开始语

一位普通的程序员,慢慢在努力变强!

没有安装seata的同学点击此处前往👈

没有安装nacos的同学点击此处前往👈

【Seata】SpringBoot集成Seata1.6-AT模式👈

简介

  • 支持XA 事务的数据库。
  • Java 应用,通过 JDBC 访问数据库。

1.描述

在 Seata 定义的分布式事务框架内,利用事务资源(数据库、消息服务等)对 XA 协议的支持,以 XA 协议的机制来管理分支事务的一种 事务模式。

  • 执行阶段:
  •     1.可回滚:业务 SQL 操作放在 XA 分支中进行,由资源对 XA 协议的支持来保证 可回滚
  •     2.持久化:XA 分支完成后,执行 XA prepare,同样,由资源对 XA 协议的支持来保证 持久化(即,之后任何意外都不会造成无法回滚的情况)
  • 完成阶段:
  •     1.分支提交:执行 XA 分支的 commit
  •     2.分支回滚:执行 XA 分支的 rollback

2.工作机制

XA 模式 运行在 Seata 定义的事务框架内:

  • 执行阶段(E xecute):
  •         XA start/XA end/XA prepare + SQL + 注册分支
  • 完成阶段(F inish):
  •         XA commit/XA rollback

3.简单总结分析

和AT模式处理相当也是二阶段提交。

第一阶段为准备阶段,TM管理器向TC协调器发送请求,开始注册全局事务,此时RM资源管理器注册分支事务,此时Order和Account两个业务链创建的SQL是未提交的,sql是执行了,但是未提交事务

第二阶段为提交、回滚阶段,当分支事务执行完毕,此时没有任何异常,那么TM管理器就向TC协调器发送一个[commit]提交请求,此时RM资源管理器就需要将事务进行提交处理。如果在一阶段其中某一个分支事务出现异常,那么第二阶段发送的请求就是[rollback],分别将RM中的order、account开始进行回滚。

代码演示

XA的使用和AT的使用是一致的!

1.配置数据源

springboot的@Configuration配置类配置

import com.alibaba.druid.pool.DruidDataSource;
import io.seata.rm.datasource.xa.DataSourceProxyXA;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.sql.DataSource;

@Configuration
public class OrderXADataSourceConfiguration {

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

    @Bean("dataSourceProxy")
    public DataSource dataSource(DruidDataSource druidDataSource) {
        // DataSourceProxy for AT mode
        // return new DataSourceProxy(druidDataSource);

        // DataSourceProxyXA for XA mode
        return new DataSourceProxyXA(druidDataSource);
    }
}

application.yml配置文件配置

seata:
  data-source-proxy-mode: XA

2.application.yml和nacos服务中的配置

#--------------nacos中的配置
spring:
  # staet----------------------------mysql服务配置
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://192.168.233.143:3306/seata_stock?allowMultiQueries=true
    username: root
    password: getianyu_ROOT_123
    type: com.alibaba.druid.pool.DruidDataSource
    druid:
      initial-size: 10
      min-idle: 10
      maxActive: 200
      maxWait: 60000
      timeBetweenEvictionRunsMillis: 60000
      minEvictableIdleTimeMillis: 300000
      validationQuery: SELECT 1 FROM DUAL
      testWhileIdle: true
      testOnBorrow: false
      testOnReturn: false
      poolPreparedStatements: true
      maxPoolPreparedStatementPerConnectionSize: 20
      connectionErrorRetryAttempts: 3
      breakAfterAcquireFailure: true
      timeBetweenConnectErrorMillis: 300000
      asyncInit: true
      remove-abandoned: false
      remove-abandoned-timeout: 1800
      transaction-query-timeout: 6000
      filters: stat,wall,log4j2
      connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000
      web-stat-filter:
        enabled: true
        url-pattern: "/*"
        exclusions: "*.js,*.gif,*.jpg,*.bmp,*.png,*.css,*.ico,/druid/*"
      stat-view-servlet:
        url-pattern: "/druid/*"
        allow:
        deny:
        reset-enable: false
        login-username: admin
        login-password: admin
# end----------------------------mysql服务配置

# staet----------------------------mybatis-plus服务配置
mybatis-plus:
  global-config:
    db-config:
      # 逻辑已删除值(默认为 1)
      logic-delete-value: 1
      # 逻辑未删除值(默认为 0)
      logic-not-delete-value: 0
  mapper-locations: classpath*:**/repository/xml/*.xml
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
    # 驼峰,_映射 app_name = appName
    map-underscore-to-camel-case: true
# end----------------------------mybatis-plus服务配置

logging:
  level:
    io.seata: debug

# staet----------------------------seata服务配置
seata:
  # 切换XA模式
  data-source-proxy-mode: XA
  config:
    type: nacos
    nacos:
      server-addr: 192.168.233.180:8848
      namespace: seata-server
      group: SEATA_GROUP
      username: nacos
      password: nacos
  registry:
    type: nacos
    nacos:
      server-addr: 192.168.233.180:8848
      namespace: seata-server
      application: seata-server
      group: SEATA_GROUP
      username: nacos
      password: nacos
  service:
    vgroup-mapping:
      default_tx_group: default
    disable-global-transaction: false
    grouplist:
      default: 192.168.233.180:8091
  tx-service-group: default_tx_group
# end----------------------------seata服务配置

#--------------application.yml中的配置
server:
  port: 9191

spring:
  application:
    name: stock-service
  profiles:
    active: @project.active@
  cloud:
    nacos:
      config:
        server-addr: @nacos.addr@
        namespace: ${spring.profiles.active}
        username: nacos
        password: nacos
        refresh-enabled: true
        enabled: true
        file-extension: yaml
        shared-configs:
          - data-id: stock-service-config.yaml
            refresh: true
      discovery:
        server-addr: @nacos.addr@
        namespace: ${spring.profiles.active}
        watch:
          enabled: true
    alibaba:
      seata:
        tx-service-group: default_tx_group

提示:上面只是stock但服务的配置,orders服务的配置和上面一致,不同的是数据库和一些springboot项目的基本信息

3.orders服务的service实现代码

/**
     * 下单:创建订单、减库存,涉及到两个服务
     *
     * @param userId
     * @param commodityCode
     * @param count
     * @param tag           commit接口如果入参是[成功],不抛出异常,[失败],抛出异常
     */
    @Override
    @GlobalTransactional
    public void placeOrder(String userId, String commodityCode, Integer count, String tag) {
        log.info("OrderService XID = {}", RootContext.getXID());
        BigDecimal orderMoney = new BigDecimal(count).multiply(new BigDecimal(5));
        Order order = new Order().setUserId(userId).setCommodityCode(commodityCode).setCount(count).setMoney(
                orderMoney);
        orderDAO.insert(order);

        // stock服务未报错,order服务报错
        try {
            stockFeignClient.deduct(commodityCode, count);
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }
        // 输入commit接口
        if ("product-1".equals(commodityCode) && tag.equals("失败")) {
            throw new RuntimeException("订单业务处理异常...");
        }

    }

4.stock服务的service实现代码

/**
     * 减库存
     *
     * @param commodityCode
     * @param count
     */
    @Transactional(rollbackFor = Exception.class)
    public void deduct(String commodityCode, int count) {
        log.info("StockService XID = {}", RootContext.getXID());

        QueryWrapper<Stock> wrapper = new QueryWrapper<>();
        wrapper.setEntity(new Stock().setCommodityCode(commodityCode));
        Stock stock = stockDAO.selectOne(wrapper);
        stock.setCount(stock.getCount() - count);

        stockDAO.updateById(stock);
        if (commodityCode.equals("product-2")) {
            throw new RuntimeException("异常:模拟业务异常:stock branch exception");
        }
    }

结果分析

在服务与服务之间调用通过XID的传输实现分布式TM进行管理,不管两个服务之间谁出现异常,那么TM发出的回滚的请求。

1.业务执行成功

双方事务最终都进行commit提交事务操作!

2.业务执行失败

在双方业务执行过程中,服务Order在执行调用Stock之后出现了异常,也就是说,他们两在SQL执行的过程中都没有出现异常,而是在业务代码中出现了异常,此时的rm收到的请求通知是双方进行回滚(rollbacked),从而保证了事务的一致性性。

XA模式的优缺点

优点:

  • 基于cp设计,强一致性,不会出现状态不一致的情况
  • 二阶段提交成熟、稳定

缺点:

  • 执行效率低,基于数据库事务处理,数据容易被锁住,也就是行锁,在简介的过程3中说过,准备阶段是将SQL执行了,但是未提交(高并发慎用)
  • 协议阻塞,在XA收到commit或者rollback前必须阻塞等待,如果在短时间内,其中一个全局事务参与者突然出现什么异常,导致一直未提交,此时需要等待超时【回滚】,从而导致性能下降
  • 网络波动,也会导致业务的行锁占用使用过长,导致当前行数据无法被使用,从而导致性能下降、业务A的SQL执行,业务B的SQL执行,但是由于B的业务链路很长,导致业务A的SQL行锁占用时间过长,导致RM锁住的资源等待越久,从而导致性能下降

适用场景

低并发、业务数据冲突少(描述:某条数据基本不会被重复执行)的应用程序

本项目代码地址

springboot-seata: springboot整合Seata分布式事务

结束语

本章节完成了,各位正在努力的程序员们,如果你们觉得本文章对您有用的话,你学到了一些东西,希望猿友们点个赞+关注,支持一下猿仁!
持续更新中…

 

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 5
    评论
### 回答1: Spring Cloud集成Seata是为了实现分布式事务的解决方案。Seata是一个开源的分布式事务解决方案,它提供了高可用性、高性能、易扩展的分布式事务服务。Spring Cloud集成Seata可以帮助我们在分布式系统中实现数据的一致性和可靠性,从而提高系统的稳定性和可靠性。在集成Seata时,我们需要配置Seata的注册中心、配置文件、数据源等信息,然后在代码中使用Seata提供的API来实现分布式事务的控制。通过Spring Cloud集成Seata,我们可以轻松地实现分布式事务的管理和控制,从而提高系统的可靠性和稳定性。 ### 回答2: Spring CloudSeata集成主要包括以下几个方面。 首先,在pom.xml文件中添加Seata的依赖项,包括seata-all、seata-spring-boot-starter和seata-spring-boot-starter-data-redis。 接下来,在配置文件中配置Seata的相关属性。需要配置seata.server.ip(Seata Server的IP地址)和seata.server.port(Seata Server的端口号),并将spring.cloud.alibaba.seata.tx-service-group设置为seata的事务组名称。 然后,在主启动类上添加@EnableAutoDataSourceProxy和@EnableFeignClients注解,开启Seata的数据源代理和Feign客户端的支持。 接着,在需要进行分布式事务管理的方法上添加@GlobalTransactional注解,指定该方法需要进行全局事务管理。 最后,在操作数据库的方法上添加@Compensable注解,用于标记该方法属于可补偿的业务操作。 通过以上步骤,就完成了Spring CloudSeata集成。在分布式事务的管理上,Seata会根据@GlobalTransactional注解来开启和提交事务,并根据@Compensable注解来进行补偿操作。此外,Seata还提供了一些额外的功能,如幂等性校验、分布式锁等,可以进一步优化分布式事务的管理和性能。 总之,Spring CloudSeata集成可以有效地解决分布式事务的一致性问题,保证系统的数据一致性和可靠性。 ### 回答3: Spring Cloud是一套用于构建分布式系统的开源框架,而Seata则是一种高性能易用的分布式事务解决方案。当我们需要在Spring Cloud集成Seata时,需要进行以下步骤: 1. 创建一个Spring Cloud项目:首先需要创建一个Spring Cloud项目,可以选择使用Spring Boot来搭建。确保项目中已经引入了Spring Cloud的相关依赖。 2. 引入Seata依赖:在项目的pom.xml文件中添加Seata的依赖。可以通过Maven或Gradle来管理项目的依赖。 3. 配置Seata相关配置文件:在项目的资源文件夹下创建一个名为"seata"的文件夹,在该文件夹下创建一个名为"registry.conf"的文件。在该文件中,配置Seata的注册中心信息和事务日志存储信息等。 4. 配置Spring CloudSeata的整合:在项目的配置文件中,配置Spring CloudSeata的整合。可以配置Seata的事务管理器、数据源代理以及相关的事务拦截器等。 5. 启动Seata服务:运行Seata的服务端,确保其正常运行。可以使用Seata提供的脚本来启动服务。 6. 编写业务代码:在项目中编写需要进行分布式事务管理的业务代码。可以使用Seata提供的注解来标注事务的边界。 7. 测试分布式事务:运行项目,并测试分布式事务的功能是否正常。通过观察日志和数据库的变化来确认分布式事务的一致性和隔离性是否得到了保证。 总的来说,集成SeataSpring Cloud需要添加依赖、配置相关文件、整合Spring CloudSeata以及编写业务代码等步骤。这样,我们就可以在Spring Cloud项目中实现分布式事务的管理,提高系统的可靠性和一致性。
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

猿仁

多一分支持,多一分动力!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值