Springcloud seata分布式事务实现代码解析

Seata 是一款开源的分布式事务解决方案,致力于提供高性能和简单易用的分布式事务服务。本篇不涉及其原理,只用代码构建项目简单试用一下其回滚的机制。

大致上seata分为TC,TM,RM三大构建成整体。它们之间的包含关系如下。即一(xid主键编码,记录信息)带三(TC,TM,RM)

下面之间构建项目进行测试。

1.下载seata并解压,然后改动配置文件。

http://seata.io/zh-cn/blog/download.html官网下载。

解压之后到conf中修改file和registry文件,修改之前一定记得先备份。

file.conf,改动两个地方

将group后面的参数定义一个名字,随意

存储方式选db放在数据库,自然其配置信息根据自己的数据库去填写。

然后是register文件,填写信息将seata注册到nacos中。

启动自然是在bin中打开bat文件即可,注意需要先启动naco。

2.构建项目(order,storage,account)

演示整体的服务调用还有服务报错的时候进入回滚。通过创建订单->检查库存并扣除->检查账户并扣除->修改订单状态

具体代码可查看GitHub

https://github.com/MaTsukun/springcloud2020

关键的service方法

@Service
@Slf4j
public class OrderServiceImpl implements OrderService{
  @Resource
  private OrderMapper orderMapper;
  @Resource
  private StorageService storageService;
  @Resource
  private AccountService accountService;

  @Override
  @GlobalTransactional(name="abc-create-order",rollbackFor = Exception.class)
  public void create(Order order){
    //1.创建订单
    log.info("开始创建订单");
    orderMapper.create(order);
    //2.减少库存
    log.info("查询库存并且进行更改");
    storageService.decrease(order.getProductId(),order.getCount());
    //3.扣除费用
    log.info("查询余额并扣除费用");
    accountService.updateAccount(order.getUserId(),order.getMoney());
    //4.修改状态
    log.info("更改订单状态");
    orderMapper.update(order.getUserId(),0);
    log.info("订单结束,O(∩_∩)O哈哈~");
  }
}

可以看到在order项目中同时调用了storage和account的项目的方法,采用的是openfeign,整体形成了一个链路,成为一个整的事务。

而添加的GlobalTransactional注解则保证了事务中任何一方出现错误就会使整个项目的执行过程进行回滚,而不是单事务的回滚。

3.seata回滚原理

在每次注解的方法里进行执行sql语句的时候都会创建一个id记录此次的写操作同时在每次的写操作前后都会生成前置记录和后置记录,可以在出现错误回滚的时候,通过记录进行逆操作回滚重新将数据写回去。

通过数据库配置的seata库展示可以看见对应的记录id信息,通过debug模式暂停服务,查看记录的信息。

global的全局xid

account表的undo记录

记录的信息json格式

{
  "@class": "io.seata.rm.datasource.undo.BranchUndoLog",
  "xid": "192.168.2.141:8091:2060193863",
  "branchId": 2060193875,
  "sqlUndoLogs": [
    "java.util.ArrayList",
    [
      {
        "@class": "io.seata.rm.datasource.undo.SQLUndoLog",
        "sqlType": "UPDATE",
        "tableName": "t_account",
        "beforeImage": {
          "@class": "io.seata.rm.datasource.sql.struct.TableRecords",
          "tableName": "t_account",
          "rows": [
            "java.util.ArrayList",
            [
              {
                "@class": "io.seata.rm.datasource.sql.struct.Row",
                "fields": [
                  "java.util.ArrayList",
                  [
                    {
                      "@class": "io.seata.rm.datasource.sql.struct.Field",
                      "name": "id",
                      "keyType": "PrimaryKey",
                      "type": -5,
                      "value": [
                        "java.lang.Long",
                        1
                      ]
                    },
                    {
                      "@class": "io.seata.rm.datasource.sql.struct.Field",
                      "name": "used",
                      "keyType": "NULL",
                      "type": 3,
                      "value": [
                        "java.math.BigDecimal",
                        600
                      ]
                    },
                    {
                      "@class": "io.seata.rm.datasource.sql.struct.Field",
                      "name": "residue",
                      "keyType": "NULL",
                      "type": 3,
                      "value": [
                        "java.math.BigDecimal",
                        400
                      ]
                    }
                  ]
                ]
              }
            ]
          ]
        },
        "afterImage": {
          "@class": "io.seata.rm.datasource.sql.struct.TableRecords",
          "tableName": "t_account",
          "rows": [
            "java.util.ArrayList",
            [
              {
                "@class": "io.seata.rm.datasource.sql.struct.Row",
                "fields": [
                  "java.util.ArrayList",
                  [
                    {
                      "@class": "io.seata.rm.datasource.sql.struct.Field",
                      "name": "id",
                      "keyType": "PrimaryKey",
                      "type": -5,
                      "value": [
                        "java.lang.Long",
                        1
                      ]
                    },
                    {
                      "@class": "io.seata.rm.datasource.sql.struct.Field",
                      "name": "used",
                      "keyType": "NULL",
                      "type": 3,
                      "value": [
                        "java.math.BigDecimal",
                        700
                      ]
                    },
                    {
                      "@class": "io.seata.rm.datasource.sql.struct.Field",
                      "name": "residue",
                      "keyType": "NULL",
                      "type": 3,
                      "value": [
                        "java.math.BigDecimal",
                        300
                      ]
                    }
                  ]
                ]
              }
            ]
          ]
        }
      }
    ]
  ]
}

可以看到里面有beforeimage和afterimage快照记录,通过这些记录可以实现逆操作,重新写进数据实现回滚。

本文只是简单的配置,后续会进行详细补充。

所有的代码都在GitHub

https://github.com/MaTsukun/springcloud2020

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • SpringCloud Gateway自定义filter获取body中的数据为空的问题

    最近在使用SpringCloud Gateway进行网关的开发,我使用的版本是:SpringBoot的2.3.4.RELEASE+SpringCloud的Hoxton.SR8,在自定义过滤器时需要获取ServerHttpRequest中body的数据,发现一直无法获取到数据,经过各种百度.谷歌,再加上自己的实践,终于找到解决方案: 1.首先创建一个全局过滤器把body中的数据缓存起来 package com.cloudpath.gateway.portal.filter; import lomb

  • SpringBoot+Dubbo+Seata分布式事务实战详解

    前言 Seata 是 阿里巴巴开源的分布式事务中间件,以高效并且对业务0侵入的方式,解决微服务场景下面临的分布式事务问题. 事实上,官方在GitHub已经给出了多种环境下的Seata应用示例项目,地址:https://github.com/seata/seata-samples. 为什么笔者要重新写一遍呢,主要原因有两点: 官网代码示例中,依赖太多,分不清哪些有什么作用 Seata相关资料较少,笔者在搭建的过程中,遇到了一些坑,记录一下 一.环境准备 本文涉及软件环境如下: SpringBoot

  • Springcloud seata nacos环境搭建过程图解

    最近学习了一下seata,由于nacos现在也挺火,于是学习了seata注册到nacos,然后集成springcloud 1.nacos配置(自行上官网下载) 将nacos/conf/nacos-mysql.sql导入自己的数据库 2.配置修改nacos/conf/application.properties spring.datasource.platform=mysql db.num=1 db.url.0=jdbc:mysql://127.0.0.1:3306/nacos?character

  • 详解SpringBoot基于Dubbo和Seata的分布式事务解决方案

    1. 分布式事务初探 一般来说,目前市面上的数据库都支持本地事务,也就是在你的应用程序中,在一个数据库连接下的操作,可以很容易的实现事务的操作. 但是目前,基于SOA的思想,大部分项目都采用微服务架构后,就会出现了跨服务间的事务需求,这就称为分布式事务. 本文假设你已经了解了事务的运行机制,如果你不了解事务,那么我建议先去看下事务相关的文章,再来阅读本文. 1.1 什么是分布式事务 对于传统的单体应用而言,实现本地事务可以依赖Spring的@Transactional注解标识方法,实现事务非常简

  • SpringCloud Alibaba Seata (收藏版)

    一.简介 官网地址: http://seata.io/zh-cn/ 1,概念 Seata是一款开源的分布式事务解决方案,致力于在微服务架构在提供高性能和简单一样的分布式事务服务. 2,处理过程 Transaction ID XID:全局唯一的事务ID Transaction Coordinator(TC) :维护全局和分支事务的状态,驱动全局事务提交或回滚. Transaction Manager™ :定义全局事务的范围:开始全局事务.提交或回滚全局事务. Resource Manager(RM

  • springcloud项目改名的操作方法

    1.原来项目结构 2.子模块改名 2.1rename操作 2.2修改子模块的pom文件 2.3修改父模块pom文件module里面子模块的名称,如果没有modules,就自己加上去 3.父模块改名字 3.1右键中父模块,Rename操作,结果如下图 3.2修改pom文件 3.3修改子模块parent标签父模块的名称(可选) 3.4退出idea 3.5重命名项目文件夹名称 3.6找到项目根目录,删除.idea文件 3.7打开idea重新导入项目即可 3.8由于删除了.idea文件,所有idea存储

  • 关于springcloud报错报UnsatisfiedDependencyException的问题

    Error starting ApplicationContext. To display the conditions report re-run your application with 'debug' enabled. 2020-11-14 00:38:14.164 ERROR 1022 --- [  restartedMain] o.s.boot.SpringApplication               : Application run failed   org.springf

  • Springcloud seata分布式事务实现代码解析

    Seata 是一款开源的分布式事务解决方案,致力于提供高性能和简单易用的分布式事务服务.本篇不涉及其原理,只用代码构建项目简单试用一下其回滚的机制. 大致上seata分为TC,TM,RM三大构建成整体.它们之间的包含关系如下.即一(xid主键编码,记录信息)带三(TC,TM,RM) 下面之间构建项目进行测试. 1.下载seata并解压,然后改动配置文件. http://seata.io/zh-cn/blog/download.html官网下载. 解压之后到conf中修改file和registry

  • tcc分布式事务框架体系解析

    目录 前言碎语 以电商下单为例 订单服务: 库存服务: 支付服务: hmily事务框架怎么做的? 实现HmilyTransactionInterceptor接口 dubbo的aspect抽象实现 dubbo的HmilyTransactionInterceptor实现 启动事务处理器处理逻辑如下 需要注意三个地方 参数者事务处理器 文末结语 前言碎语 楼主之前推荐过2pc的分布式事务框架LCN.今天来详细聊聊TCC事务协议. 首先我们了解下什么是tcc,如下图 tcc分布式事务协议控制整体业务事务

  • SpringCloud Alibaba使用Seata处理分布式事务的技巧

    Seata简介 在传统的单体项目中,我们使用@Transactional注解就能实现基本的ACID事务了. 但是前提是: 1) 数据库支持事务(如:MySQL的innoDB引擎) 2) 所有业务都在同一个数据库中执行 随着微服务架构的引入,需要对数据库进行分库分表,每个服务拥有自己的数据库,这样传统的事务就不起作用了,那么我们如何保证多个服务中数据的一致性呢? 这样就出现了分布式事务,而Seata就是为微服务架构而生的一种高性能.易于使用的分布式事务解决方案. Seata 中有三个基础组件: T

  • springboot cloud使用eureka整合分布式事务组件Seata 的方法

    前言 近期一直在忙项目,我也是打工仔.不多说,我们开始玩一玩seata. 正文 什么都不说,我们按照惯例,先上一个图(图里不规范的使用请忽略): 简单一眼就看出来, 比我们平时用的东西,多了 Seata Server 微服务 . 同样这个 Seata Server 微服务 ,也是需要注册到eureka上面去的. 那么我们首先就搞一搞这个 seata server ,那么剩下的就是一些原本的业务服务整合配置了. 该篇用的 seata server 版本,用的是1.4.1 , 可以去git下载下.当

  • SpringCloud+RocketMQ实现分布式事务的实践

    目录 一.RocketMQ的分布式事务结构和说明 二.搭建RocketMQ 三.事务场景,然后准备工程,运行代码 随着互联网公司的微服务越来越多,分布式事务已经成为了我们的经常使用的.所以我们来一步一步的实现基于RocketMQ的分布式事务.接下来,我们将要做的主题写出来. RocketMQ的分布式事务结构和说明 搭建RocketMQ步骤 事务场景,然后准备工程,运行代码 一.RocketMQ的分布式事务结构和说明 我们通过下图来了解一下RocketMQ实现分布式事务的结构.采用半消息机制实现分

  • SpringCloud微服务开发基于RocketMQ实现分布式事务管理详解

    目录 消息队列实现分布式事务原理 RocketMQ的事务消息 代码实现 基础配置 发送半消息 执行本地事务与回查 Account-Service消费消息 测试 小结 消息队列实现分布式事务原理 首先让我们来看一下基于消息队列实现分布式事务的原理方案. 柔性事务 发送消息的服务有个OUTBOX数据表,在进行INSERT.UPDATE.DELETE 业务操作时也会给OUTBOX数据表INSERT一条消息记录,这样可以保证原子性,因为这是基于本地的ACID事务. OUTBOX表充当临时消息队列,然后我

  • springboot整合shardingsphere和seata实现分布式事务的实践

    各个框架版本信息 springboot: 2.1.3 springcloud: Greenwich.RELEASE seata: 1.0.0 shardingsphere:4.0.1 maven 依赖        <dependency>         <!--<groupId>io.shardingsphere</groupId>-->         <groupId>org.apache.shardingsphere</group

  • Java分布式事务管理框架之Seata

    目录 Seata介绍 三大组件 实现原理 四种事务模式 搭建seata服务端 单机版安装 集群安装 Seata介绍 Seata:Simple Extensible Autonomous Transaction Architecture,简易可扩展的自治式分布式事务管理框架,其前身是fescar.是一种简单分布式事务的解决方案.Seata 是一款开源的分布式事务解决方案,致力于提供高性能和简单易用的分布式事务服务.Seata 将为用户提供了 AT.TCC.SAGA 和 XA 事务模式,为用户打造一

随机推荐