SpringCloud Alibaba(六) - Seata 分散式事務鎖

化羽羽發表於2022-12-03

1、Seata 簡介

1.1 Seata是什麼

Seata 是一款開源的分散式事務解決方案,致力於提供高效能和簡單易用的分散式事務服務。Seata 將為使用者提供了 AT、TCC、SAGA 和 XA 事務模式,為使用者打造一站式的分散式解決方案。AT模式是阿里首推的模式,阿里雲上有商用版本的GTS(Global Transaction Service 全域性事務服務)。

1.2 Seata的三大角色

在Seata的架構中,一共有三大角色:

TC(Transaction Coordinator)- 事務協調者

維護全域性和分支事務的狀態,驅動全域性事務提交或回滾。

TM(Transaction Manager)- 事務管理器

定義全域性事務的範圍:開始全域性事務、提交或回滾全域性事務

RM(Resource Manager)- 資源管理器

管理分支事務處理的資源,與TC交談以註冊分支事務和報告分支事務的狀態,並驅動分支事務提交或回滾。

其中,TC為單獨部署的Server服務端,TM和RM為嵌入到應用中的Client客戶端。

1.3 一個分散式事務的生命週期

部落格參考:https://blog.csdn.net/qq_41910252/article/details/122517092

2、安裝seata

2.1 下載安裝包和原始碼

下載地址:https://github.com/seata/seata/releases

2.2 修改registry,conf 上傳配置檔案到nacos

2.2.1 複製 registry 檔案

2.2.2 修改配置

2.3 上傳到nacos的配置列表

 使用git視窗# sh nacos-config.sh -h localhost -p 8848

資料庫8的修改一下driverClassName

加時區:

2.3 修改config.txt 啟動seate 註冊到nacos

2.3.1 複製config.txt

2.3.2 修改config.txt

2.3.3 建立seata資料庫

2.3.4 啟動seata

seata-server.bat -h 127.0.0.1 -p 8091

3、專案演示

3.1 模組說明

3.2 依賴

<!-- nacso註冊,feign 依賴不再贅述 -->
<!--   seata     -->
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-seata</artifactId>
</dependency>

3.4 配置

3.4.1 undo_log表

3.2.1.1 資料庫指令碼

3.2.1.2 配置
# 服務名
spring:
  # 資料來源配置
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/seate_order?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=GMT
    username: root
    password: root
    initialization-mode: always # 支援微服務應用啟動時自動執行schema。sql指令碼
3.2.1.3 後面專案啟動後指令碼刷入order庫,和prod庫

3.4.2 seata配置

# seata client配置(頂格寫)
seata:
  enabled: true # 開啟Seata
  tx-service-group: my_test_tx_group # 事務服務分組(可以每個應用單獨取名, 也可以使用相同的名字)即要和上文中的seata-server的context.txt中service.vgroupMapping.seata_test_tx_group=default一致
  enable-auto-data-source-proxy: true # 自動開啟資料來源代理
  registry:
    type: nacos # 使用nacos註冊中心,預設file,訪問seata server(TC)
    nacos:
      server-addr: 127.0.0.1:8848 # seata server 所在的nacos服務地址
      application: seata-server # seata server 的服務名seata-server ,如果沒有修改可以不配
      group: SEATA_GROUP # seata server 所在的組,預設就是SEATA_GROUP,沒有改也可以不配
  config:
    type: nacos
    nacos:
      server-addr: 127.0.0.1:8848 # seata server 所在的nacos服務地址
      group: SEATA_GROUP # seata server 所在的組,預設就是SEATA_GROUP,沒有改也可以不配
  service:
    vgroup-mapping:
      my_test_tx_group: default # 事務群組(必須與seata-server保持一致)
    disable-global-transaction: false # 是否禁用全域性事務開關
  client:
    rm:
      report-success-enable: false #是否上報一階段成功

3.5 主要程式碼

3.5.1 order模組的下單和遠端呼叫扣減庫存

全域性事務註解:@GlobalTransactional

/**
 * Created On : 1/12/2022.
 * <p>
 * Author : huayu
 * <p>
 * Description: order模組 下單,呼叫遠端扣減庫存
 */
@Service
@Slf4j
public class KgcMallSeataOrderServiceImpl implements KgcMallSeataOrderService {
    
    @Autowired
    private KgcMallSeataOrderRepository kgcMallSeataOrderRepository; //執行 下單

    @Autowired
    private KgcMallSeataProdFeignService kgcMallSeataProdFeignService;  // 遠端呼叫 執行 扣減庫存

    @Override
    @GlobalTransactional // 分散式事務註解,使用的全域性事務,後續所有微服務涉及事務操作,都會被統一管理
    public KgcMallSeataOrder createSeataOrder(KgcMallSeataOrder kgcMallSeataOrder, Integer count) {

        //將分散式事務訂單入庫
        KgcMallSeataOrder seataOrder = kgcMallSeataOrderRepository.save(kgcMallSeataOrder);

        //遠端呼叫商品業務介面,扣減庫存
        kgcMallSeataProdFeignService.invokeSeataProductStockFeign(kgcMallSeataOrder.getProdId(), count);

        //返回下單詳情
        return seataOrder;
    }

}

3.5.2 prod 模組 扣減庫存

事務註解:@Transactional

/**
 * Created On : 1/12/2022.
 * <p>
 * Author : huayu
 * <p>
 * Description: prod模組 扣減庫存
 */
@Service
public class KgcMallProdServiceImpl implements KgcMallProdService {

    @Autowired
    private KgcMallSeataProdRepository kgcMallSeataProdRepository; //執行 扣減庫存

    @Override
    @Transactional
    public KgcMallSeataProduct subSeataProductStock(Integer pid, Integer count) {

        //查詢商品庫存
        KgcMallSeataProduct kgcMallSeataProduct = kgcMallSeataProdRepository.findById(pid).orElse(null);

        //判斷商品是否存在
        if (kgcMallSeataProduct != null) {
            kgcMallSeataProduct.setProdStock(kgcMallSeataProduct.getProdStock() - count);
        }
        KgcMallSeataProduct saveKgcMallSeataProduct = kgcMallSeataProdRepository.save(kgcMallSeataProduct);

        //模擬執行時異常
        if (count == 10) {
            int a = 10 / 0;
        }

        //返回詳情
        return saveKgcMallSeataProduct;
    }

}

4 測試

4.1 正常下單

4.1.1 發起請求

4.1.2 檢視資料庫

order資料庫下單:

prod資料庫扣減庫存:

扣減前:

扣減後:

4.2 模擬執行時異常

4.2.1 發起請求

4.2.2 檢視資料庫




相關文章