1. 程式人生 > 程式設計 >Springcloud seata分散式事務實現程式碼解析

Springcloud seata分散式事務實現程式碼解析

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","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
                      ]
                    },"name": "residue",400
                      ]
                    }
                  ]
                ]
              }
            ]
          ]
        },"afterImage": {
          "@class": "io.seata.rm.datasource.sql.struct.TableRecords",700
                      ]
                    },300
                      ]
                    }
                  ]
                ]
              }
            ]
          ]
        }
      }
    ]
  ]
}

可以看到裡面有beforeimage和afterimage快照記錄,通過這些記錄可以實現逆操作,重新寫進資料實現回滾。

本文只是簡單的配置,後續會進行詳細補充。

所有的程式碼都在GitHub

https://github.com/MaTsukun/springcloud2020

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支援我們。