天天看点

【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模式