Springcloud中的分布式事务怎么利用seata实现
创始人
2024-11-21 16:22:02
0次

Seata 是一款开源的分布式事务解决方案,致力于提供高性能和简单易用的分布式事务服务。

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

Springcloud中的分布式事务怎么利用seata实现

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

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

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

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

file.conf,改动两个地方

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

Springcloud中的分布式事务怎么利用seata实现

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

Springcloud中的分布式事务怎么利用seata实现

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

Springcloud中的分布式事务怎么利用seata实现

启动自然是在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

Springcloud中的分布式事务怎么利用seata实现

account表的undo记录

Springcloud中的分布式事务怎么利用seata实现

记录的信息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快照记录,通过这些记录可以实现逆操作,重新写进数据实现回滚。

相关内容

热门资讯

空调连续工作多久需要停机休息 空调连续工作的时间取决于多个因素,包括空调的型号、功率、使用环境和维护情况等。一般来说,空调可以连续...
空调哪个符号是除湿的 空调除湿功能通常用一个水滴形状的符号表示。不同品牌和型号的空调遥控器可能会有所差异,但一般来说,除湿...
格力空调多长时间加一次氟利昂 1、一般情况下,空调对氟利昂的使用量是非常小的,所以在空调使用了四年左右的时候再考虑加也没问题。2、...
空调用多长时间需要加氟一次 一般情况下是五年。当出现以下这几种情况时,空调才需要加氟。1、空调的室内机和室外机各有两个接口,当接...
格调生活·C标思享荟:卡萨帝在... 9月12日的郑州龙湖金融岛,夜风轻拂,灯光璀璨。“C标时刻共传奇——卡萨帝思享荟暨20周年品牌盛典郑...
品牌价值破千亿、高端份额持续领... 9月12日,“C标时刻共传奇——卡萨帝思享荟暨20周年品牌盛典郑州站”在郑州龙湖金融岛举办。2026...
空调主板坏了修800还是换新的 空调主板坏了是修还是换新,需要考虑多个因素,以下是一些建议:1. 维修成本:如果维修费用较低,比如 ...
空调开多久需要休息多长时间 问题:空调开多久需要休息多长时间回答:1、在使用空调的过程中,一般空调开7~8个小时左右需要休息2~...
中央空调多长时间清洗一次 1、一般空调开机前清洗一次即可,空调开机中间时段再清洗一次,空调关机时清洗一次,这样比较合理。2、空...
中央空调氟利昂多久加一次 看空调制热和制冷程度,很多人的观点认为氟利昂必须一年放一次,其实这个观点是错误的,理解上面有点偏差,...