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

 更新时间:2020年12月07日 14:47:40   作者:梦泽千秋  
这篇文章主要介绍了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

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

相关文章

  • Mybatis-Plus-AutoGenerator 最详细使用方法

    Mybatis-Plus-AutoGenerator 最详细使用方法

    这篇文章主要介绍了Mybatis-Plus-AutoGenerator 最详细使用方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-03-03
  • 基于Java实现音乐播放器的示例代码

    基于Java实现音乐播放器的示例代码

    这篇文章主要为大家详细介绍了如何利用Java编写一个简单的音乐播放器,文中的示例代码讲解详细,具有一定的学习价值,感兴趣的小伙伴可以了解一下
    2023-07-07
  • SpringCloud微服务应用config配置中心详解

    SpringCloud微服务应用config配置中心详解

    这篇文章主要介绍了SpringCloud微服务应用-config配置中心,包括相关知识介绍、搭建、动态刷新、测试,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2022-07-07
  • Unity2019-2020 个人版官方免费激活详细方法

    Unity2019-2020 个人版官方免费激活详细方法

    这篇文章主要介绍了Unity2019-2020 个人版官方免费激活详细方法,激活方法分位两种一种是激活新许可证,一种是手动激活,感兴趣的朋友跟随小编一起看看吧
    2021-04-04
  • Java线程同步方法实例总结

    Java线程同步方法实例总结

    这篇文章主要介绍了Java线程同步方法,结合实例形式总结分析了Java线程同步、并发控制相关实现方法及操作注意事项,需要的朋友可以参考下
    2018-08-08
  • Jackson中json格式的字符串与对象的互相转换方式

    Jackson中json格式的字符串与对象的互相转换方式

    这篇文章主要介绍了Jackson中json格式的字符串与对象的互相转换方式,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-07-07
  • 浅析JVM垃圾回收的过程

    浅析JVM垃圾回收的过程

    这篇文章主要介绍了JVM垃圾回收的过程,帮助大家更好的理解和学习Java中的垃圾回收机制,感兴趣的朋友可以了解下
    2020-09-09
  • 后端java压缩图片超详细图文教程

    后端java压缩图片超详细图文教程

    这篇文章主要给大家介绍了关于后端java压缩图片的相关资料,片压缩是一种广泛采用的技术,它不仅能显著减小文件大小,释放更多存储空间,还能提升图片加载速度,避免长时间等待,需要的朋友可以参考下
    2024-04-04
  • 使用@PathVariable注解如何实现动态传值

    使用@PathVariable注解如何实现动态传值

    这篇文章主要介绍了使用@PathVariable注解如何实现动态传值,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-10-10
  • java参数传值代码举例

    java参数传值代码举例

    在编程中往方法中传递参数的方法往往有两种,一种是值传递,一种是引用传递,而在java中所有的参数传递全部都是值传递,这篇文章主要给大家介绍了关于java参数传值的相关资料,需要的朋友可以参考下
    2024-03-03

最新评论