天天看點

【Spring Cloud、Seata、Nacos】搭建Spirng Cloud項目(十一):Spring Cloud使用Seata(TCC) 解決分布式事務問題一、環境準備二、服務提供方(seata-b-server)準備三、服務調用方準備四、啟動服務,調用測試接口後效果五、問題總結六、拓展

一、環境準備

1、環境搭建,檢視Spring Cloud專欄

2、seate-server運作成功,參考文章:【Seata、Nacos】Win安裝Seata,并整合Nacos、【Docker】安裝 Seata Server

3、準備一個服務提供方(seata-b-server)的接口和服務調用方(seata-a-server)接口,本文兩個服務之間調用通過OpenFegin,可參考前文。

二、服務提供方(seata-b-server)準備

  • 提供TestTccController類
package com.cyun.seata.b.controller;

import com.cyun.core.result.ResultVO;
import io.seata.rm.tcc.api.BusinessActionContext;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;

import java.math.BigDecimal;

/**
 * 服務提供者,提供接口(TCC)
 *
 * @author He PanFu
 * @date 2022-03-17 20:38:18
 */
@Slf4j
@RestController
@RequestMapping("/test/tcc")
@RequiredArgsConstructor
public class TestTccController {

    @PostMapping("/add")
    public ResultVO prepare(@RequestBody BusinessActionContext context, @RequestParam("id") String id,
                            @RequestParam("name") String name) {
        log.info("請求進入準備階段,參數資訊:id={},name={}", id, name);
        return ResultVO.ok();
    }

    @PostMapping("/add/commit")
    public boolean commitTcc(@RequestBody BusinessActionContext context) {
        log.info("請求進入送出階段,xid = {}", context.getXid());
        return true;
    }

    @PostMapping("/add/cancel")
    public boolean cancel(@RequestBody BusinessActionContext context) {
        // 這裡寫中間件、非關系型資料庫的復原操作
        log.info("請求進入復原階段,xid = {}", context.getXid());
        return true;
    }
}

           

三、服務調用方準備

  • 提供測試類入口TestTccController
package com.cyun.seata.a.controller;

import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.cyun.core.result.ResultVO;
import com.cyun.seata.a.entity.A;
import com.cyun.seata.a.feign.service.ISeataBServerService;
import com.cyun.seata.a.feign.service.ISeataTccBServerService;
import com.cyun.seata.a.service.IAService;
import io.seata.rm.tcc.api.BusinessActionContext;
import io.seata.spring.annotation.GlobalTransactional;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * 服務調用者:測試入口
 *
 * @author He PanFu
 * @date 2022-03-17 20:38:18
 */
@Slf4j
@RestController
@RequestMapping("/test/tcc")
@RequiredArgsConstructor
public class TestTccController {

    private final ISeataTccBServerService seataTccBServerService;

    @GetMapping(value = "/add")
    @GlobalTransactional
    public ResultVO testAdd() {
        seataTccBServerService.prepare(null,"1","張三");
        return ResultVO.ok();
    }

}

           
  • OpenFeig服務
package com.cyun.seata.a.feign.service;

import com.cyun.core.result.ResultVO;
import io.seata.rm.tcc.api.BusinessActionContext;
import io.seata.rm.tcc.api.BusinessActionContextParameter;
import io.seata.rm.tcc.api.LocalTCC;
import io.seata.rm.tcc.api.TwoPhaseBusinessAction;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.*;

import java.math.BigDecimal;

/**
 * seata-b-server 服務提供的接口
 *
 * @author He PanFu
 * @date 2022-03-17 21:07:40
 */
@SuppressWarnings("All")
@FeignClient(value = "seata-b-server")
@LocalTCC
public interface ISeataTccBServerService {


    @PostMapping("/seata_b_server/test/tcc/add")
    @TwoPhaseBusinessAction(name = "prepare", commitMethod = "commitTcc", rollbackMethod = "cancel")
    public ResultVO prepare(@RequestBody BusinessActionContext context, @BusinessActionContextParameter(paramName = "id") @RequestParam("id") String id,
                            @BusinessActionContextParameter(paramName = "name") @RequestParam("name") String name);

    @PostMapping("/seata_b_server/test/tcc/add/commit")
    public boolean commitTcc(@RequestBody BusinessActionContext context);

    @PostMapping("/seata_b_server/test/tcc/add/cancel")
    public boolean cancel(@RequestBody BusinessActionContext context);
}

           
  • 相關介紹
@LocalTCC:适用于SpringCloud+Feign模式下的TCC
@TwoPhaseBusinessAction:注解try方法,其中name為目前tcc方法的bean名稱,寫方法名便可(記得全局唯一),commitMethod指向送出方法,rollbackMethod指向事務復原方法。指定好三個方法之後,seata會根據全局事務的成功或失敗,去幫我們自動調用送出方法或者復原方法。
@BusinessActionContextParameter:注解可以将參數傳遞到二階段(commitMethod/rollbackMethod)的方法。
BusinessActionContext:便是指TCC事務上下文
           

四、啟動服務,調用測試接口後效果

  • 服務提供者控制台日子
    【Spring Cloud、Seata、Nacos】搭建Spirng Cloud項目(十一):Spring Cloud使用Seata(TCC) 解決分布式事務問題一、環境準備二、服務提供方(seata-b-server)準備三、服務調用方準備四、啟動服務,調用測試接口後效果五、問題總結六、拓展

五、問題總結

  • 自定義commit()和自定義cancel()方法必須是boolean傳回值類型,不然會報錯,并且一直重試。
  • 提供者提供的接口不能是get類型的,否則也會報錯,并會直接進入到自定義cancel()方法。提示

六、拓展

相關文章推薦:

Seata分布式事務方案TCC模式