Seata(分佈式事務解決方案)快速開始

在這裏插入圖片描述

版本

  • SpringBoot:2.2.5.RELEASE
  • SpringCloud:Hoxton.SR3
  • SpringCloudAlibaba:2.2.1.RELEASE
  • Nacos Server:1.2.1
  • Seata Server:1.1.0
  • Jdk:1.8

部署

0:下載Nacos Server和Seata Server

https://github.com/alibaba/nacos/releases
https://github.com/seata/seata/releases

1:部署Nacos Server

Nacos快速開始:https://blog.csdn.net/momo57l/article/details/104298206
Nacos集羣部署:https://blog.csdn.net/momo57l/article/details/104737165

2:部署Seata Server
第一步:修改conf/registry.conf:註冊中心和配置中心都改爲使用nacos,serverAddr填nacos地址,namespace是nacos中的命名空間,默認不填是default,config下的group是nacos中的分組,默認是SEATA_GROUP,也可以改成其他分組

registry {
  type = "nacos"

  nacos {
    serverAddr = "localhost"
    namespace = "90f980dc-c419-4be2-95a2-85d5c73deccb"
    cluster = "default"
  }
}

config {
  type = "nacos"

  nacos {
    serverAddr = "localhost"
    namespace = "90f980dc-c419-4be2-95a2-85d5c73deccb"
    group = "SEATA_GROUP"
  }
}

第二步:下載所需腳本文件:都在github script文件夾下,需要下載維護seata事務信息的mysql.sqlseata配置文件config.txt將seata配置文件導入nacos的導入腳本
下載完成後將會得到三個文件:mysql.sql、config.txt和nacos-config.sh(或者nacos-config.py)

第三步:修改config.txt

# 將存儲seata事務信息的方式改爲db存儲
store.mode=db
# 改爲新建或者現有數據庫配置信息
store.db.datasource=dbcp
store.db.dbType=mysql
store.db.driverClassName=com.mysql.jdbc.Driver
store.db.url=jdbc:mysql://127.0.0.1:3306/db_seata_0420?useUnicode=true
store.db.user=root
store.db.password=root
store.db.minConn=1
store.db.maxConn=3
store.db.globalTable=global_table
store.db.branchTable=branch_table
store.db.queryLimit=100
store.db.lockTable=lock_table

第四步:執行mysql.sql:在第三步配置的數據庫中執行SQL文件後得到三張表,分別是lock_table、branch_table、global_table

第五步:將config.txt導入至nacos:我這裏是window環境,所以使用的是nacos-config.py這個腳本,在控制檯執行python .\nacos-config.py localhost:8848即可完成導入,Linux環境可以使用nacos-config.sh腳本,導入過程有問題的話建議先打開導入腳本看下config.txt目錄是否正確。數據導入到nacos後是在默認的命名空間

第六步:將導入至nacos中的config.txt信息遷移至對應的命名空間(namespace):在第一步中registry.conf文件裏填寫了對應的namespace,如果是默認的則可以跳過該步驟。遷移方式是先導出再到對應的命名空間中執行導入,然後刪除之前命名空間中的配置信息即可,注意要將SEATA_GROUP的配置信息全部勾選
在這裏插入圖片描述
第七步:啓動Seata Server:windows環境下直接在控制檯執行.\seata-server.bat即可啓動。Linux環境下可以使用seata-server.sh -h 127.0.0.1 -p 8091 -m db -n 1 -e test指令啓動。啓動完成後在nacos服務列表中就可以看到seata服務了

  • -h: 註冊到註冊中心的ip
  • -p: Server rpc 監聽端口
  • -m: 全局事務會話信息存儲模式,file、db,優先讀取啓動參數
  • -n: Server node,多個Server時,需區分各自節點,用於生成不同區間的transactionId,以免衝突
  • -e: 多環境配置參考 http://seata.io/en-us/docs/ops/multi-configuration-isolation.html

在這裏插入圖片描述

食用

0:項目搭建
第一步:引入相關依賴,包括jpa、nacos、seata、web等

# nacos只需要服務發現的客戶端,如果要使用配置中心的話可以再引入nacos-config
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>

# seata客戶端依賴
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-seata</artifactId>
</dependency>

第二步:創建兩個微服務,分別是demo-orde(訂單服務)和demo-payment(支付服務),支付服務中有創建支付單業務,訂單服務中有創建訂單業務,創建訂單操作會通過feign client調用支付服務中的創建支付單業務,兩個業務分別處於各自本地事務中

訂單服務中的創建訂單

/**
 * 創建訂單業務,會通過feign client調用支付服務中的創建支付單業務
 * 爲了方便測試,orderBo中有個flag字段,可以控制下面這個異常是否執行
 */
@GlobalTransactional
@Transactional(rollbackOn = Exception.class)
public void createOrder(OrderBO orderBo) {
    OrderPO po = new OrderPO();
    po.setOrderCode("TEST" + System.currentTimeMillis());
    po.setOrderAmount(orderBo.getOrderAmount());
    orderRepository.save(po);

    paymentFeignClient.createOrderPayment(OrderPaymentBO.builder()
            .orderId(po.getId())
            .orderAmount(orderBo.getOrderAmount())
            .build());

    if (orderBo.getFlag()) {
        throw new RuntimeException("demo order exception.");
    }
}

支付服務中的創建支付單業務

/**
 * 支付服務中的創建支付單業務
 */
@Transactional(rollbackOn = Exception.class)
public void createOrderPayment(OrderPaymentBO orderPaymentBo) {
    OrderPaymentPO po = new OrderPaymentPO();
    po.setOrderId(orderPaymentBo.getOrderId());
    po.setOrderAmount(orderPaymentBo.getOrderAmount());
    orderPaymentRepository.save(po);
}

主要配置信息,注意nacos配置下的namespace要跟之前配置的namespace一致。seata配置下的tx-service-group需要手動指定,其中service.vgroup-mapping.${tx-service-group}配置成default

server:
  port: 8095

seata:
  tx-service-group: ${spring.application.name}
  service:
    vgroup-mapping:
      demo-order: default

spring:
  application:
    name: demo-order

  cloud:
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848
        namespace: 90f980dc-c419-4be2-95a2-85d5c73deccb

第三步:測試,如果兩個業務分別處於各自本地事務,在創建訂單業務中,如果通過feign client調用支付服務之後發生異常的話,支付服務的業務是不會回滾的

POST localhost:8095/order/create-order
{
	"orderAmount":100,
	"flag":true
}

結果跟預期一致,訂單表沒有新增記錄,支付單新增了一條記錄

第四步:引入seata,只需要在訂單業務上加上@GlobalTransactional註解即可,這時兩個業務將處於同一個全局事務中,如果訂單調用支付後發生異常,則兩者都會回滾

@GlobalTransactional
@Transactional(rollbackOn = Exception.class)
public void createOrder(OrderBO orderBo) {
    OrderPO po = new OrderPO();
    po.setOrderCode("TEST" + System.currentTimeMillis());
    po.setOrderAmount(orderBo.getOrderAmount());
    orderRepository.save(po);

    paymentFeignClient.createOrderPayment(OrderPaymentBO.builder()
            .orderId(po.getId())
            .orderAmount(orderBo.getOrderAmount())
            .build());

    if (orderBo.getFlag()) {
        throw new RuntimeException("demo order exception.");
    }
}

此時異常發生後,兩個業務都會回滾

補充:SEATA AT 模式需要 UNDO_LOG 表支持,所有我們需要在業務數據庫中新增一張UNDO_LOG 表

-- 注意此處0.3.0+ 增加唯一索引 ux_undo_log
CREATE TABLE `undo_log` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `branch_id` bigint(20) NOT NULL,
  `xid` varchar(100) NOT NULL,
  `context` varchar(128) NOT NULL,
  `rollback_info` longblob NOT NULL,
  `log_status` int(11) NOT NULL,
  `log_created` datetime NOT NULL,
  `log_modified` datetime NOT NULL,
  `ext` varchar(100) DEFAULT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `ux_undo_log` (`xid`,`branch_id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;

鏈接

Seata:http://seata.io/zh-cn/
Spring Cloud Alibaba:https://spring.io/projects/spring-cloud-alibaba

案例

Gitee:https://gitee.com/liujiazhongg_admin/seata-nacos-example

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章