SpringCloud Alibaba微服务实战七 - 分布式事务

简介: SpringCloud Alibaba微服务实战七 - 分布式事务

导读:本篇作为SpringCloud Alibaba微服务实战系列的第七篇,主要内容是使用Seata解决分布式事务问题。系列文章,欢迎持续关注。


场景说明


订单服务order-service需要对外提供创建订单的接口,创建订单的业务逻辑如下:

先调用本地的orderService保存订单操作,然后通过feign调用远程的accout-service进行账户余额扣减,最后再通过feign调用远程的product-service进行库存扣减操作。

关键的逻辑代码如下:

  • OrderController对外提供创建订单的接口
@PostMapping("/order/create")
public ResultData<OrderDTO> create(@RequestBody OrderDTO orderDTO){
  log.info("create order:{}",orderDTO);
  orderDTO.setOrderNo(UUID.randomUUID().toString());
  orderDTO.setAmount(orderDTO.getPrice().multiply(new BigDecimal(orderDTO.getCount())));
  orderService.createOrder(orderDTO);
  return ResultData.success("create order success");
}
  • OrderServiceImpl负责处理创建订单的业务逻辑
@Transactional(rollbackFor = RuntimeException.class)
@Override
public void createOrder(OrderDTO orderDTO) {
  Order order = new Order();
  BeanUtils.copyProperties(orderDTO,order);
  //本地存储Order
  this.saveOrder(order);
  //库存扣减
  productFeign.deduct(orderDTO.getProductCode(),order.getCount());
  //账户余额扣减
  accountFeign.reduce(orderDTO.getAccountCode(), orderDTO.getAmount());
}
@Transactional(rollbackFor = RuntimeException.class)
void saveOrder(Order order) {
  orderMapper.insert(order);
}

本地先保存订单,然后调用两个远程服务进行扣减操作。

  • AccountServiceImpl扣减账户余额
@Transactional(rollbackFor = RuntimeException.class)
@Override
public void reduceAccount(String accountCode, BigDecimal amount) {
  Account account = accountMapper.selectByCode(accountCode);
  if(null == account){
    thrownew RuntimeException("can't reduce amount,account is null");
  }
  BigDecimal subAmount = account.getAmount().subtract(amount);
  if(subAmount.compareTo(BigDecimal.ZERO) < 0){
    thrownew RuntimeException("can't reduce amount,account'amount is less than reduce amount");
  }
  account.setAmount(subAmount);
  accountMapper.updateById(account);
}

做些简单的校验,当账户余额不足的时候不允许扣减操作。

  • ProductServiceImpl扣减产品库存
@Transactional(rollbackFor = RuntimeException.class)
@Override
public void deduct(String productCode, Integer deductCount) {
  Product product = productMapper.selectByCode(productCode);
  if(null == product){
    thrownew RuntimeException("can't deduct product,product is null");
  }
  int surplus = product.getCount() - deductCount;
  if(surplus < 0){
    thrownew RuntimeException("can't deduct product,product's count is less than deduct count");
  }
  product.setCount(surplus);
  productMapper.updateById(product);
}

做些简单的校验,当产品库存不足时不允许扣减操作。

order-serviceproduct-serviceaccount-service分属不同的服务,当其中一个服务抛出异常无法提交时就会导致分布式事务,如当使用feign调用account-service执行扣减账户余额时,account-service校验账户余额不足抛出异常,但是order-service的保存操作不会回滚;或者是前两步执行成功但是product-service校验不通过前面的操作也不会回滚,这就导致了数据不一致,也就是分布式事务问题!


Seata解决方案


在Springcloud Alibaba体系中使用Seata作为分布式事务解决方案,大家可以访问seata官网去了解详情。这次我们先使用Seata的file配置解决上面出现的问题,后面再来对其改造。


下载安装Seata Server。

  • 从 Release 页面下载Seata Server
  • 下载完成后直接启动Server端服务。
    在Linux/Mac下
    $ sh ./bin/seata-server.sh
    在Windows下
    bin\seata-server.bat

引入seata组件

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


在配置文件中增加seata配置

spring:
  cloud:
    alibaba:
      seata:
        tx-service-group:${spring.application.name}-seata


Seata Client 配置修改

  • 将Seata Server 配置目录下的registry.conffile.conf 2个文件拷贝到微服务中的resources文件夹下
  • 修改拷贝后的registry.conf
registry{
  type = "file"
  file {
    name = "file.conf"
  }
}
config{
  type = "file"
  file {
    name = "file.conf"
  }
}
  • 修改file.conf主要修改如下三处:
    service.vgroup_mapping.后面的值修改为配置文件spring.cloud.alibaba.seata.tx-service-group的属性
    service.default.grouplist=修改为Seata Server的ip:端口
    support.spring.datasource.autoproxy的值修改为true,开启datasource自动代理

生成undo_log表

在微服务的业务库下执行如下语句,生成undo_log表

-- 此脚本必须初始化在你当前的业务数据库中,用于AT 模式XID记录。与server端无关(注:业务数据库)
droptable`undo_log`;
CREATETABLE`undo_log` (
  `id`bigint(20) NOTNULL AUTO_INCREMENT,
  `branch_id`bigint(20) NOTNULL,
  `xid`varchar(100) NOTNULL,
  `context`varchar(128) NOTNULL,
  `rollback_info` longblob NOTNULL,
  `log_status`int(11) NOTNULL,
  `log_created` datetime NOTNULL,
  `log_modified` datetime NOTNULL,
  `ext`varchar(100) DEFAULTNULL,
  PRIMARY KEY (`id`),
  UNIQUEKEY`ux_undo_log` (`xid`,`branch_id`)
) ENGINE=InnoDB AUTO_INCREMENT=1DEFAULTCHARSET=utf8;


开启全局事务

在分布式事务方法入口添加注解@GlobalTransactional,这里只需要在createOrder方法上添加此注解即可!

@GlobalTransactional(name = "TX_ORDER_CREATE")
@Override
public void createOrder(OrderDTO orderDTO) {
  Order order = new Order();
  BeanUtils.copyProperties(orderDTO,order);
  //本地存储Order
  this.saveOrder(order);
  log.info("ORDER XID is: {}", RootContext.getXID());
  //账户余额扣减
  accountFeign.reduce(orderDTO.getAccountCode(), orderDTO.getAmount());
  //库存扣减
  productFeign.deduct(orderDTO.getProductCode(),orderDTO.getCount());
}

在代码中可以使用RootContext.getXID()获取全局xid


启动服务

服务正常启动后在Seata Server控制台可以看到注册信息


接口测试

改造完成后对接口进行测试,如果其他服务抛出异常会看到如下错误日志,再结合数据库数据观察是否正常回滚

执行过程中我们通过debug可以发现undo_log表会不断插入数据,在执行后又会被删除。

通过上面几步我们使用Seata实现了分布式事务,保证了数据的一致性,最后说一句Seata真香,你们要不要感受一下。至此本期的“SpringCloud Alibaba微服务实战七 - 分布式事务”篇也就该结束啦,咱们下期有缘再见!


目录
相关文章
|
监控 Java API
Spring Boot 3.2 结合 Spring Cloud 微服务架构实操指南 现代分布式应用系统构建实战教程
Spring Boot 3.2 + Spring Cloud 2023.0 微服务架构实践摘要 本文基于Spring Boot 3.2.5和Spring Cloud 2023.0.1最新稳定版本,演示现代微服务架构的构建过程。主要内容包括: 技术栈选择:采用Spring Cloud Netflix Eureka 4.1.0作为服务注册中心,Resilience4j 2.1.0替代Hystrix实现熔断机制,配合OpenFeign和Gateway等组件。 核心实操步骤: 搭建Eureka注册中心服务 构建商品
1519 3
|
10月前
|
负载均衡 Java API
《深入理解Spring》Spring Cloud 构建分布式系统的微服务全家桶
Spring Cloud为微服务架构提供一站式解决方案,涵盖服务注册、配置管理、负载均衡、熔断限流等核心功能,助力开发者构建高可用、易扩展的分布式系统,并持续向云原生演进。
|
Java 关系型数据库 数据库
微服务——SpringBoot使用归纳——Spring Boot事务配置管理——常见问题总结
本文总结了Spring Boot中使用事务的常见问题,虽然通过`@Transactional`注解可以轻松实现事务管理,但在实际项目中仍有许多潜在坑点。文章详细分析了三个典型问题:1) 异常未被捕获导致事务未回滚,需明确指定`rollbackFor`属性;2) 异常被try-catch“吃掉”,应避免在事务方法中直接处理异常;3) 事务范围与锁范围不一致引发并发问题,建议调整锁策略以覆盖事务范围。这些问题看似简单,但一旦发生,排查难度较大,因此开发时需格外留意。最后,文章提供了课程源代码下载地址,供读者实践参考。
483 0
|
Java 关系型数据库 数据库
微服务——SpringBoot使用归纳——Spring Boot事务配置管理——Spring Boot 事务配置
本文介绍了 Spring Boot 中的事务配置与使用方法。首先需要导入 MySQL 依赖,Spring Boot 会自动注入 `DataSourceTransactionManager`,无需额外配置即可通过 `@Transactional` 注解实现事务管理。接着通过创建一个用户插入功能的示例,展示了如何在 Service 层手动抛出异常以测试事务回滚机制。测试结果表明,数据库中未新增记录,证明事务已成功回滚。此过程简单高效,适合日常开发需求。
1943 0
|
Java 数据库 微服务
微服务——SpringBoot使用归纳——Spring Boot事务配置管理——事务相关
本文介绍Spring Boot事务配置管理,阐述事务在企业应用开发中的重要性。事务确保数据操作可靠,任一异常均可回滚至初始状态,如转账、购票等场景需全流程执行成功才算完成。同时,事务管理在Spring Boot的service层广泛应用,但根据实际需求也可能存在无需事务的情况,例如独立数据插入操作。
375 0
|
存储 JavaScript 开发工具
基于HarmonyOS 5.0(NEXT)与SpringCloud架构的跨平台应用开发与服务集成研究【实战】
本次的.HarmonyOS Next ,ArkTS语言,HarmonyOS的元服务和DevEco Studio 开发工具,为开发者提供了构建现代化、轻量化、高性能应用的便捷方式。这些技术和工具将帮助开发者更好地适应未来的智能设备和服务提供方式。
基于HarmonyOS 5.0(NEXT)与SpringCloud架构的跨平台应用开发与服务集成研究【实战】
|
Java Nacos Sentinel
Spring Cloud Alibaba:一站式微服务解决方案
Spring Cloud Alibaba(简称SCA) 是一个基于 Spring Cloud 构建的开源微服务框架,专为解决分布式系统中的服务治理、配置管理、服务发现、消息总线等问题而设计。
3431 13
Spring Cloud Alibaba:一站式微服务解决方案
|
存储 SpringCloudAlibaba Java
【SpringCloud Alibaba系列】一文全面解析Zookeeper安装、常用命令、JavaAPI操作、Watch事件监听、分布式锁、集群搭建、核心理论
一文全面解析Zookeeper安装、常用命令、JavaAPI操作、Watch事件监听、分布式锁、集群搭建、核心理论。
【SpringCloud Alibaba系列】一文全面解析Zookeeper安装、常用命令、JavaAPI操作、Watch事件监听、分布式锁、集群搭建、核心理论
|
Java 关系型数据库 数据库
微服务SpringCloud分布式事务之Seata
SpringCloud+SpringCloudAlibaba的Seata实现分布式事务,步骤超详细,附带视频教程
1278 1
|
人工智能 文字识别 Java
SpringCloud+Python 混合微服务,如何打造AI分布式业务应用的技术底层?
尼恩,一位拥有20年架构经验的老架构师,通过其深厚的架构功力,成功指导了一位9年经验的网易工程师转型为大模型架构师,薪资逆涨50%,年薪近80W。尼恩的指导不仅帮助这位工程师在一年内成为大模型架构师,还让他管理起了10人团队,产品成功应用于多家大中型企业。尼恩因此决定编写《LLM大模型学习圣经》系列,帮助更多人掌握大模型架构,实现职业跃迁。该系列包括《从0到1吃透Transformer技术底座》、《从0到1精通RAG架构》等,旨在系统化、体系化地讲解大模型技术,助力读者实现“offer直提”。此外,尼恩还分享了多个技术圣经,如《NIO圣经》、《Docker圣经》等,帮助读者深入理解核心技术。
SpringCloud+Python 混合微服务,如何打造AI分布式业务应用的技术底层?

热门文章

最新文章