【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
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

猿仁

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

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

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

打赏作者

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

抵扣说明:

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

余额充值