springboot整合nacos1.2.0与seata1.2.0具体实现分布式事务流程

2023-11-04

前言:关于nacos与seata以及springboot的基本配置与pom文件整合请看上篇文章 nacos1.2.0整合seata1.2.0最新版

这里直接介绍具体使用方法:

1.结构大致如下

2.测试controller

package com.vincent.spring_cloud_seata_order.Controller;

import com.vincent.spring_cloud_seata_order.Service.OrderService;
import com.vincent.spring_cloud_seata_order.entity.Order;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;

import java.math.BigDecimal;
import java.util.Date;

@Controller
@RequestMapping("/order")
public class OrderController {

    @Autowired
    private OrderService orderService;


    @RequestMapping(value = "/test",method = RequestMethod.GET)
    @ResponseBody
    public Integer test(){
        //限流
        try {
            orderService.beginOrder();
            return  1;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return -1;
    }
}

3.测试feign,这里调度是另一个服务goods服务,goods也是简单的访问新增处理

package com.vincent.spring_cloud_seata_order.Feign;

import com.vincent.spring_cloud_seata_order.Feign.Fallback.GoodsFeignRollBack;
import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;

@FeignClient(value = "goods",fallback = GoodsFeignRollBack.class)
public interface GoodsFeign  {

    @RequestMapping(value = "/goods/test",method = RequestMethod.GET)
    public String test();

//    @RequestMapping(value = "/goods/searchGoods",method = RequestMethod.GET)
//    public String SearchGoods(@RequestParam("goodsId") Integer goodsId);

}

3.1 goods服务的controller代码

package com.vincent.spring_cloud_seata_goods.Controller;

import com.vincent.spring_cloud_seata_goods.Serivce.GoodsService;
import com.vincent.spring_cloud_seata_goods.Util.Result;
import com.vincent.spring_cloud_seata_goods.entity.Goods;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.UUID;

@Controller
@RequestMapping("/goods")
public class GoodsController {

    @Autowired
    private GoodsService goodsService;

    @RequestMapping("/test")
    @ResponseBody
    public Integer test(){
        //限流
        try {
            Goods goods=new Goods();
            goods.setName("测试商品"+ UUID.randomUUID());
            goods.setCreateTime(new Date());
            goodsService.save(goods);
            return  goods.getId();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return -1;
    }

}

4.Aop切面处理类

package com.vincent.spring_cloud_seata_order.Util;

import io.seata.core.context.RootContext;
import io.seata.core.exception.TransactionException;
import io.seata.tm.api.GlobalTransaction;
import io.seata.tm.api.GlobalTransactionContext;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;

@Aspect
@Component
public class FeignTransactionalAop {
    //访问方法前进入处理
    @Before("execution(* com.vincent.spring_cloud_seata_order.Service.*.*(..))")
    public void before(JoinPoint joinPoint) throws TransactionException {
        MethodSignature signature = (MethodSignature)joinPoint.getSignature();
        Method method = signature.getMethod();
        System.out.println("拦截到需要分布式事务的方法"+method.getName());
        GlobalTransaction tx = GlobalTransactionContext.getCurrentOrCreate();
        // 超时时间 , 所在服务
        tx.begin(300000, "order");

    }
    //抛出异常后加入处理,手动回滚全局事务
    @AfterThrowing(throwing = "e", pointcut = "execution(* com.vincent.spring_cloud_seata_order.Service.*.*(..))")
    public void doRecoveryActions(Throwable e) throws TransactionException {
        System.out.println("方法执行异常");
        if (!StringUtils.isBlank(RootContext.getXID())) {
            GlobalTransactionContext.reload(RootContext.getXID()).rollback();
        }
    }


}

5.测试service类

package com.vincent.spring_cloud_seata_order.Service.Impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.vincent.spring_cloud_seata_order.Feign.GoodsFeign;
import com.vincent.spring_cloud_seata_order.Service.OrderService;
import com.vincent.spring_cloud_seata_order.entity.Order;
import com.vincent.spring_cloud_seata_order.mapper.obj.OrderMapper;
import io.seata.spring.annotation.GlobalTransactional;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.UUID;

@Service
public class OrderServiceImpl extends ServiceImpl<OrderMapper, Order> implements OrderService {

    @Autowired
    private GoodsFeign goodsFeign;

    @Autowired
    private OrderMapper orderMapper;

    @Override
    @GlobalTransactional(rollbackFor = Exception.class)
    public String beginOrder() {
            Order order=new Order();
            order.setName("测试订单:"+ UUID.randomUUID());
            order.setOriginalPrice(new BigDecimal("100"));
            System.out.println("订单服务开始插入数据");
            orderMapper.insert(order);
            System.out.println("开始调度商品服务插入test");
            String goodsMsg=goodsFeign.test();
            //seata当处理完多个并行服务时候,会对seata数据库3表做操作,也同对并行服务undo_log表进行操作
            if(!goodsMsg.equals("熔断器触发")) {
                System.out.println("模拟测试熔断器");
                throw new RuntimeException();
            }

        return "success";
    }
}

6.访问测试order服务 http://localhost:11100/order/test

并且debug端点卡住

8.yml文件

server:
  port: 11100
spring:
  application:
    name: order
  datasource:
    type: com.alibaba.druid.pool.DruidDataSource
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://192.168.116.130:3306/order?useUnicode=true&characterEncoding=UTF-8&zeroDateTimeBehavior=convertToNull&useSSL=false&serverTimezone=GMT%2B8
    username: root
    password: 123456
  cloud:
    nacos:
      discovery:
        server-addr: http://192.168.116.130:8848
    alibaba:
      seata:
        tx-service-group: order-service-group
##seata配置,相当于registry.conf
seata:
  client:
    support:
      spring:
        datasource-autoproxy: true
  tx-service-group: order-service-group
  service:
    disable-global-transaction: false
    grouplist:
      default: 192.168.116.130:8091
  registry:
    type: nacos
    nacos:
      server-addr: 192.168.116.130
  config:
    nacos:
      server-addr: 192.168.116.130
    type: nacos
##设置feign超时时间,否则时间过短,造成数据不一致问题
ribbon:
  ConnectTimeout: 10000 # ribbon链接超时时长
  ReadTimeout: 10000 # ribbon读取超时时间长
mybatis-plus:
  #  configuration:mybatis.mapper-locations=classpath:mapper/*.xml
  #    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
  mapper-locations: classpath:/mybatis/mappers/obj/*Mapper.xml
  #实体扫描,多个package用逗号或者分号分隔
  typeAliasesPackage: com.vincent.spring_cloud_seata_order.entity
  global-config:
    # 数据库相关配置
    db-config:
      #主键类型  AUTO:"数据库ID自增", INPUT:"用户输入ID",ID_WORKER:"全局唯一ID (数字类型唯一ID)", UUID:"全局唯一ID UUID";
      id-type: UUID
      #字段策略 IGNORED:"忽略判断",NOT_NULL:"非 NULL 判断"),NOT_EMPTY:"非空判断"
      field-strategy: not_empty
      #驼峰下划线转换
      column-underline: true
      #数据库大写下划线转换
      #capital-mode: true
      # 逻辑删除配置
      logic-delete-value: 0
      logic-not-delete-value: 1
      db-type: mysql
    #刷新mapper 调试神器
    refresh: true
management:
  endpoints:
    web:
      exposure:
        include: "*"

9.pom文件

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.2.6.RELEASE</version>
		<relativePath/> <!-- lookup parent from repository -->
<!--		<groupId>org.springframework.boot</groupId>-->
<!--		<artifactId>spring-boot-starter-parent</artifactId>-->
<!--		<version>2.1.6.RELEASE</version>-->
<!--		<relativePath>../spring_cloud_alibaba_dependence/pom.xml</relativePath>-->
	</parent>
	<groupId>com.vincent</groupId>
	<artifactId>spring_cloud_seata_order</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<name>spring_cloud_seata_order</name>
	<description>Demo project for Spring Boot</description>

	<properties>
		<java.version>1.8</java.version>
		<nacos.version>2.2.1.RELEASE</nacos.version>
<!--		<boot.version>2.2.6.RELEASE</boot.version>-->
		<feign.version>2.2.2.RELEASE</feign.version>
	</properties>

	<dependencies>
<!--		<dependency>-->
<!--			<groupId>org.springframework.boot</groupId>-->
<!--			<artifactId>spring-boot-starter-parent</artifactId>-->
<!--			<version>2.1.7.RELEASE</version>-->
<!--		</dependency>-->
		<dependency>
			<groupId>org.projectlombok</groupId>
			<artifactId>lombok</artifactId>
			<optional>true</optional>
		</dependency>

<!--		Seata 包-->
		<dependency>
			<groupId>com.alibaba.cloud</groupId>
			<artifactId>spring-cloud-starter-alibaba-seata</artifactId>
			<version>2.2.1.RELEASE</version>
			<exclusions>
				<exclusion>
					<groupId>io.seata</groupId>
					<artifactId>seata-all</artifactId>
				</exclusion>
				<exclusion>
					<groupId>io.seata</groupId>
					<artifactId>seata-spring-boot-starter</artifactId>
				</exclusion>
			</exclusions>
		</dependency>
		<dependency>
			<groupId>io.seata</groupId>
			<artifactId>seata-spring-boot-starter</artifactId>
			<version>1.2.0</version>
		</dependency>

		<dependency>
			<groupId>com.alibaba</groupId>
			<artifactId>druid</artifactId>
			<version>1.1.22</version>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
<!--			<version>${boot.version}</version>-->
		</dependency>
		<!--openfeign 支持解析MVC注解接口-->
		<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-starter-openfeign</artifactId>
			<version>${feign.version}</version>
		</dependency>
		<!--Nacos配置-->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-actuator</artifactId>
		</dependency>
		<dependency>
			<groupId>com.alibaba.cloud</groupId>
			<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
			<version>2.2.1.RELEASE</version>
		</dependency>

<!--		<dependency>-->
<!--			<groupId>com.alibaba.cloud</groupId>-->
<!--			<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>-->
<!--			<version>${nacos.version}</version>-->
<!--		</dependency>-->

		<!--ORM-->
		<!-- 集成mysql -->
		<dependency>
			<groupId>mysql</groupId>
			<artifactId>mysql-connector-java</artifactId>
			<scope>runtime</scope>
		</dependency>
		<dependency>
			<groupId>com.baomidou</groupId>
			<artifactId>mybatis-plus-boot-starter</artifactId>
			<version>3.3.1.tmp</version>
			<exclusions>
				<exclusion>
					<groupId>com.github.jsqlparser</groupId>
					<artifactId>jsqlparser</artifactId>
				</exclusion>
			</exclusions>
		</dependency>
	</dependencies>


	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
		</plugins>
	</build>

</project>

10.查询seata服务表的数据,

11.查询order业务库与goods业务库的unlock表

12.再次查询业务库里业务数据是否正常,发现此时两边业务库数据都输入正常了

13.由于我在代码最后面手动抛出了运行异常,然后由aop负责截取进行手动处理

14.于是乎数据库显示如下,发现两业务表数据都已经回滚成功了,说明全局事务真正生效了

 

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

springboot整合nacos1.2.0与seata1.2.0具体实现分布式事务流程 的相关文章

随机推荐