0
点赞
收藏
分享

微信扫一扫

Springcloud集成Seata分布式事务

登高且赋 2022-04-13 阅读 47

Springcloud集成Seata分布式事务

一、环境

二、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">
   ……
   <dependencies>
	<!--nacos 服务注册/发现 客户端-->
	<dependency>
	  <groupId>com.alibaba.cloud</groupId>
	  <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
	</dependency>
	<dependency>
	  <groupId>com.alibaba.cloud</groupId>
	  <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
	</dependency>
	<!--seata分布式事务-->
	<dependency>
	  <groupId>com.alibaba.cloud</groupId>
	  <artifactId>spring-cloud-starter-alibaba-seata</artifactId>
	  <exclusions>
            <exclusion>
              <groupId>com.alibaba</groupId>
	       <artifactId>druid</artifactId>
	    </exclusion>
	  </exclusions>
	</dependency>
   </dependencies>
    ……
</project>

三、applicaton.yml配置

# spring 相关配置
spring:
  cloud:
    alibaba:
      seata:
        # seata分组配置
        tx-service-group: my_test_tx_group
# seata分布式事务配置
seata:
  # 注册中心配置
  registry:
    # 注册中心类型,这里采用alibaba的nacos
    type: nacos
    nacos:
      # 服务名
      application: seata-server
      # nacos注册中的地址,此处配置多个时默认集群模式
      server-addr: 192.168.0.28:8844,192.168.0.28:8846,192.168.0.28:8848
      # nacos用户密码
      username: nacos
      password: nacos
      # 分组名
      group: SEATA_GROUP
      # 命名空间ID值
      namespace: 637b036c-75a2-4afb-9ccd-2716ece04ffd
  # 配置中心
  config:
    # 配置中心类型,这里采用alibaba的nacos
    type: nacos
    nacos:
      # 配置中心地址,此处配置多个时模式集群模式
      server-addr: 192.168.0.28:8844,192.168.0.28:8846,192.168.0.28:8848
      # 配置中心用户名和密码
      username: nacos
      password: nacos
      # 分组名
      group: SEATA_GROUP
      # 命名空间
      namespace: 637b036c-75a2-4afb-9ccd-2716ece04ffd

四、商品服务

  • OrderController.java
package com.jwssw.order.controller;

import com.jwssw.order.provider.StockServiceProvider;
import com.jwssw.order.service.OrderService;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

/**
 * 类描述:对外提供服务类
 *
 * @author 鲁浩鹏 Lu Haopeng
 * @version 1.0
 * @email <a href="mailTo:luhaopeng2005@126.com">Lu Haopeng</a>
 * @date 2022/3/19 10:43
 * @since JDK 8
 */
@RestController
@RequestMapping("/order")
public class OrderController {
    /** restTemplate远程调用对象 */
    private final RestTemplate restTemplate;
    /** openfeign远程调用对象 */
    private final StockServiceProvider stockService;
    /** 订单服务接口 */
    private final OrderService orderService;

    /**
     * 构造方法注入
     */
    public OrderController(RestTemplate restTemplate, StockServiceProvider stockService, OrderService orderService) {
        this.restTemplate = restTemplate;
        this.stockService = stockService;
        this.orderService = orderService;
    }

    /**
     * 增加订单同时减少库存
     */
    @RequestMapping("/insert")
    public String insert(@RequestParam("num") int num) {
        // 调用接口
        return orderService.reduct(num);
    }
}

  • OrderService.java类
package com.jwssw.order.service;

import com.baomidou.mybatisplus.extension.service.IService;
import com.jwssw.order.domain.entity.JwsswOrder;

/**
 * 类描述:
 *
 * @author 鲁浩鹏 Lu Haopeng
 * @version 1.0
 * @email <a href="mailTo:luhaopeng2005@126.com">Lu Haopeng</a>
 * @date 2022/4/5 16:26
 * @slogan 优良的架构是演进而来的,非设计出来的
 * @since JDK 8
 */
public interface OrderService extends IService<JwsswOrder> {
    // 增加订单同时减少库存
    String reduct(int num);
}
  • OrderServiceImpl.java类
package com.jwssw.order.service.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.jwssw.order.domain.entity.JwsswOrder;
import com.jwssw.order.mapper.OrderMapper;
import com.jwssw.order.provider.StockServiceProvider;
import com.jwssw.order.service.OrderService;
import io.seata.spring.annotation.GlobalTransactional;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

import java.util.Date;
import java.util.Random;

/**
 * 类描述:
 *
 * @author 鲁浩鹏 Lu Haopeng
 * @version 1.0
 * @email <a href="mailTo:luhaopeng2005@126.com">Lu Haopeng</a>
 * @date 2022/4/5 16:26
 * @slogan 优良的架构是演进而来的,非设计出来的
 * @since JDK 8
 */
@Service
public class OrderServiceImpl extends ServiceImpl<OrderMapper, JwsswOrder> implements OrderService {

    /** restTemplate远程调用对象 */
    private final RestTemplate restTemplate;
    private final StockServiceProvider stockServiceProvider;

    /**
     * 构造方法注入
     */
    public OrderServiceImpl(RestTemplate restTemplate, StockServiceProvider stockServiceProvider) {
        this.restTemplate = restTemplate;
        this.stockServiceProvider = stockServiceProvider;
    }

    @GlobalTransactional // 该注解是seata实现分布式事务的关键主键
    @Override
    public String reduct(int num) {
        // 本地数据库保存订单
        JwsswOrder order = new JwsswOrder();
        order.setId(new Random().nextInt(100000));
        order.setContext("cethis");
        order.setCreateDate(new Date().toString());
        baseMapper.insert(order);

        // 调用库存微服务接口(openfeign远程调用)
        String reduct = stockServiceProvider.reduce(1);
        // 模拟失败,主要是除0
        int i = 1 / num;
        return reduct;
    }
}
  • StockServiceProvider.java类
package com.jwssw.order.provider;

import com.jwssw.order.provider.fallback.StockServiceFallback;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;

/**
 * 类描述:openfeign远程调用接口类
 *
 * @author 鲁浩鹏 Lu Haopeng
 * @version 1.0
 * @email <a href="mailTo:luhaopeng2005@126.com">Lu Haopeng</a>
 * @date 2022/3/24 09:53
 * @since JDK 8
 */
@FeignClient(name = "stock-server", fallbackFactory = StockServiceFallback.class)
public interface StockServiceProvider {
    /**
     * 方法描述: 调用stock服务的reduct接口的方法
     *
     * @return {@link String}
     * @author 鲁浩鹏 Lu Haopeng
     * @date 2022/3/25 14:23
     */
    @PostMapping("/stock/reduce")
    String reduce(@RequestParam("stockId") int stockId);
}
  • StockServiceFallback类
package com.jwssw.order.provider.fallback;

import com.jwssw.order.provider.StockServiceProvider;
import feign.hystrix.FallbackFactory;
import org.springframework.stereotype.Component;

/**
 * 类描述:
 *
 * @author 鲁浩鹏 Lu Haopeng
 * @version 1.0
 * @email <a href="mailTo:luhaopeng2005@126.com">Lu Haopeng</a>
 * @date 2022/4/5 16:33
 * @slogan 优良的架构是演进而来的,非设计出来的
 * @since JDK 8
 */
@Component
public class StockServiceFallback implements FallbackFactory<StockServiceFactory> {

    @Override
    public StockServiceFactory create(Throwable cause) {
        return new StockServiceFactory();
    }
}
/**
 * 错误回调工厂类
 */
class StockServiceFactory implements StockServiceProvider {
    /**
     * 方法描述: 调用stock服务的reduct接口的方法
     *
     * @return {@link String}
     * @author 鲁浩鹏 Lu Haopeng
     * @date 2022/3/25 14:23
     */
    @Override
    public String reduce(int stockId) {
        return "库存服务不可达";
    }
}
  • JwsswOrder.java类
package com.jwssw.order.domain.entity;

import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.ToString;

import java.io.Serializable;


/**
 * 类描述:
 *
 * @author 鲁浩鹏 Lu Haopeng
 * @version 1.0
 * @email <a href="mailTo:luhaopeng2005@126.com">Lu Haopeng</a>
 * @date 2022/4/5 16:02
 * @slogan 优良的架构是演进而来的,非设计出来的
 * @since JDK 8
 */
@Data
@NoArgsConstructor
@AllArgsConstructor
@ToString
@TableName("jwssw_order")
public class JwsswOrder implements Serializable {
    @TableId
    private int id;
    private String createDate;
    private String context;
}
  • OrderMapper.java类
package com.jwssw.order.mapper;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.jwssw.order.domain.entity.JwsswOrder;

/**
 * 类描述:
 *
 * @author 鲁浩鹏 Lu Haopeng
 * @version 1.0
 * @email <a href="mailTo:luhaopeng2005@126.com">Lu Haopeng</a>
 * @date 2022/4/5 16:22
 * @slogan 优良的架构是演进而来的,非设计出来的
 * @since JDK 8
 */
public interface OrderMapper extends BaseMapper<JwsswOrder> {
}

五、库存服务

  • StockController
package com.jwssw.stock.controller;

import com.jwssw.stock.domain.entity.JwsswStock;
import com.jwssw.stock.service.StockService;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

/**
 * 类描述:对外提供服务类
 *
 * @author 鲁浩鹏 Lu Haopeng
 * @version 1.0
 * @email <a href="mailTo:luhaopeng2005@126.com">Lu Haopeng</a>
 * @date 2022/3/19 10:46
 * @since JDK 8
 */
@RestController
@RequestMapping("/stock")
public class StockController {

    /** 获取配置文件中的端口号 */
    @Value("${server.port}")
    private String port;

    private final StockService stockService;

    public StockController(StockService stockService) {
        this.stockService = stockService;
    }

    @PostMapping("/reduce")
    public String reduce(@RequestParam("stockId") int stockId) {
        boolean update = stockService.lambdaUpdate().setSql("stock_number=stock_number -1")
                .eq(JwsswStock::getId, stockId).update();
        return update ? "扣减库存成功" : "扣减库存失败";
    }
}
  • StockService.java
package com.jwssw.stock.service;

import com.baomidou.mybatisplus.extension.service.IService;
import com.jwssw.stock.domain.entity.JwsswStock;

/**
 * 类描述:
 *
 * @author 鲁浩鹏 Lu Haopeng
 * @version 1.0
 * @email <a href="mailTo:luhaopeng2005@126.com">Lu Haopeng</a>
 * @date 2022/4/5 18:32
 * @slogan 优良的架构是演进而来的,非设计出来的
 * @since JDK 8
 */
public interface StockService extends IService<JwsswStock> {
}
  • StockServiceImpl.java
package com.jwssw.stock.service.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.jwssw.stock.domain.entity.JwsswStock;
import com.jwssw.stock.mapper.StockMapper;
import com.jwssw.stock.service.StockService;
import org.springframework.stereotype.Service;

/**
 * 类描述:
 *
 * @author 鲁浩鹏 Lu Haopeng
 * @version 1.0
 * @email <a href="mailTo:luhaopeng2005@126.com">Lu Haopeng</a>
 * @date 2022/4/5 18:33
 * @slogan 优良的架构是演进而来的,非设计出来的
 * @since JDK 8
 */
@Service
public class StockServiceImpl extends ServiceImpl<StockMapper, JwsswStock> implements StockService {
}
  • StockMapper.java
package com.jwssw.stock.mapper;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.jwssw.stock.domain.entity.JwsswStock;

/**
 * 类描述:
 *
 * @author 鲁浩鹏 Lu Haopeng
 * @version 1.0
 * @email <a href="mailTo:luhaopeng2005@126.com">Lu Haopeng</a>
 * @date 2022/4/5 18:32
 * @slogan 优良的架构是演进而来的,非设计出来的
 * @since JDK 8
 */
public interface StockMapper extends BaseMapper<JwsswStock> {
}
  • JwsswStock.java
package com.jwssw.stock.domain.entity;

import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Builder;
import lombok.Data;

/**
 * 类描述:
 *
 * @author 鲁浩鹏 Lu Haopeng
 * @version 1.0
 * @email <a href="mailTo:luhaopeng2005@126.com">Lu Haopeng</a>
 * @date 2022/4/5 18:30
 * @slogan 优良的架构是演进而来的,非设计出来的
 * @since JDK 8
 */
@Data
@Builder
@TableName("jwssw_stock")
public class JwsswStock {
    private int id;
    private String orderName;
    private int stockNumber;
}

六、测试

  • OrderControllerTest.java
package com.jwssw.order;

import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.context.ApplicationContext;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.RequestBuilder;
import org.springframework.test.web.servlet.ResultActions;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;

import static org.junit.jupiter.api.Assertions.*;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;

/**
 * 类描述:单元测试类
 *
 * @author 鲁浩鹏 Lu Haopeng
 * @version 1.0
 * @email <a href="mailTo:luhaopeng2005@126.com">Lu Haopeng</a>
 * @date 2022/3/24 09:26
 * @since JDK 8
 */
@ExtendWith(SpringExtension.class)
@SpringBootTest
@AutoConfigureMockMvc
class OrderControllerTest {

    @Autowired
    private MockMvc mvc;

    @Test
    void add() throws Exception {
        // 调用controller中的接口
        ResultActions resultActions = mvc.perform(get("/order/insert").param("num", "1"))
                .andDo(print())
                .andExpect(status().isOk());
       // 输出结果
       System.out.println(resultActions.andReturn().getResponse().getContentAsString());
    }
}
举报

相关推荐

0 条评论