日本免费高清视频-国产福利视频导航-黄色在线播放国产-天天操天天操天天操天天操|www.shdianci.com

學(xué)無(wú)先后,達(dá)者為師

網(wǎng)站首頁(yè) 編程語(yǔ)言 正文

Springcloud集成Seata分布式事務(wù)

作者:Rewloc 更新時(shí)間: 2022-05-11 編程語(yǔ)言

Springcloud集成Seata分布式事務(wù)

一、環(huán)境

開(kāi)發(fā)工具:idea
springcloud版本:Hoxton.SR12
springboot版本:2.3.12.RELEASE
springcloud alibaba版本:2.2.7.RELEASE
seata版本:2.2.7.RELEASE
Seata單機(jī)部署、 Seata集群部署 和 nginx代理nacos集群

二、pom文件依賴(lài)

主要給出核心依賴(lài),其他依賴(lài)自行引入,不如springcloud、springcloudalibaba等等


<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>
	
	<dependency>
	  <groupId>com.alibaba.cloudgroupId>
	  <artifactId>spring-cloud-starter-alibaba-nacos-discoveryartifactId>
	dependency>
	<dependency>
	  <groupId>com.alibaba.cloudgroupId>
	  <artifactId>spring-cloud-starter-alibaba-nacos-configartifactId>
	dependency>
	
	<dependency>
	  <groupId>com.alibaba.cloudgroupId>
	  <artifactId>spring-cloud-starter-alibaba-seataartifactId>
	  <exclusions>
            <exclusion>
              <groupId>com.alibabagroupId>
	       <artifactId>druidartifactId>
	    exclusion>
	  exclusions>
	dependency>
   dependencies>
    ……
project>

三、applicaton.yml配置

配置文件關(guān)于nacos的配置,可以參考Nginx代理Nacos集群進(jìn)行配置

自行配置數(shù)據(jù)配置和端口信息

# spring 相關(guān)配置
spring:
  cloud:
    alibaba:
      seata:
        # seata分組配置
        tx-service-group: my_test_tx_group
# seata分布式事務(wù)配置
seata:
  # 注冊(cè)中心配置
  registry:
    # 注冊(cè)中心類(lèi)型,這里采用alibaba的nacos
    type: nacos
    nacos:
      # 服務(wù)名
      application: seata-server
      # nacos注冊(cè)中的地址,此處配置多個(gè)時(shí)默認(rèn)集群模式
      server-addr: 192.168.0.28:8844,192.168.0.28:8846,192.168.0.28:8848
      # nacos用戶(hù)密碼
      username: nacos
      password: nacos
      # 分組名
      group: SEATA_GROUP
      # 命名空間ID值
      namespace: 637b036c-75a2-4afb-9ccd-2716ece04ffd
  # 配置中心
  config:
    # 配置中心類(lèi)型,這里采用alibaba的nacos
    type: nacos
    nacos:
      # 配置中心地址,此處配置多個(gè)時(shí)模式集群模式
      server-addr: 192.168.0.28:8844,192.168.0.28:8846,192.168.0.28:8848
      # 配置中心用戶(hù)名和密碼
      username: nacos
      password: nacos
      # 分組名
      group: SEATA_GROUP
      # 命名空間
      namespace: 637b036c-75a2-4afb-9ccd-2716ece04ffd

四、商品服務(wù)

  • 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;

/**
 * 類(lèi)描述:對(duì)外提供服務(wù)類(lèi)
 *
 * @author 魯浩鵬 Lu Haopeng
 * @version 1.0
 * @email Lu Haopeng
 * @date 2022/3/19 10:43
 * @since JDK 8
 */
@RestController
@RequestMapping("/order")
public class OrderController {
    /** restTemplate遠(yuǎn)程調(diào)用對(duì)象 */
    private final RestTemplate restTemplate;
    /** openfeign遠(yuǎn)程調(diào)用對(duì)象 */
    private final StockServiceProvider stockService;
    /** 訂單服務(wù)接口 */
    private final OrderService orderService;

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

    /**
     * 增加訂單同時(shí)減少庫(kù)存
     */
    @RequestMapping("/insert")
    public String insert(@RequestParam("num") int num) {
        // 調(diào)用接口
        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;

/**
 * 類(lèi)描述:
 *
 * @author 魯浩鵬 Lu Haopeng
 * @version 1.0
 * @email Lu Haopeng
 * @date 2022/4/5 16:26
 * @slogan 優(yōu)良的架構(gòu)是演進(jìn)而來(lái)的,非設(shè)計(jì)出來(lái)的
 * @since JDK 8
 */
public interface OrderService extends IService<JwsswOrder> {
    // 增加訂單同時(shí)減少庫(kù)存
    String reduct(int num);
}
  • OrderServiceImpl.java

@GlobalTransactional 該注解是seata實(shí)現(xiàn)分布式事務(wù)的關(guān)鍵注解,將該注解直接作用于方法上即可。

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;

/**
 * 類(lèi)描述:
 *
 * @author 魯浩鵬 Lu Haopeng
 * @version 1.0
 * @email Lu Haopeng
 * @date 2022/4/5 16:26
 * @slogan 優(yōu)良的架構(gòu)是演進(jìn)而來(lái)的,非設(shè)計(jì)出來(lái)的
 * @since JDK 8
 */
@Service
public class OrderServiceImpl extends ServiceImpl<OrderMapper, JwsswOrder> implements OrderService {

    /** restTemplate遠(yuǎn)程調(diào)用對(duì)象 */
    private final RestTemplate restTemplate;
    private final StockServiceProvider stockServiceProvider;

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

    @GlobalTransactional // 該注解是seata實(shí)現(xiàn)分布式事務(wù)的關(guān)鍵主鍵
    @Override
    public String reduct(int num) {
        // 本地?cái)?shù)據(jù)庫(kù)保存訂單
        JwsswOrder order = new JwsswOrder();
        order.setId(new Random().nextInt(100000));
        order.setContext("cethis");
        order.setCreateDate(new Date().toString());
        baseMapper.insert(order);

        // 調(diào)用庫(kù)存微服務(wù)接口(openfeign遠(yuǎn)程調(diào)用)
        String reduct = stockServiceProvider.reduce(1);
        // 模擬失敗,主要是除0
        int i = 1 / num;
        return reduct;
    }
}
  • StockServiceProvider.java

該類(lèi)作用就是通過(guò)openfeign調(diào)用庫(kù)存服務(wù)中的接口

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;

/**
 * 類(lèi)描述:openfeign遠(yuǎn)程調(diào)用接口類(lèi)
 *
 * @author 魯浩鵬 Lu Haopeng
 * @version 1.0
 * @email Lu Haopeng
 * @date 2022/3/24 09:53
 * @since JDK 8
 */
@FeignClient(name = "stock-server", fallbackFactory = StockServiceFallback.class)
public interface StockServiceProvider {
    /**
     * 方法描述: 調(diào)用stock服務(wù)的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;

/**
 * 類(lèi)描述:
 *
 * @author 魯浩鵬 Lu Haopeng
 * @version 1.0
 * @email Lu Haopeng
 * @date 2022/4/5 16:33
 * @slogan 優(yōu)良的架構(gòu)是演進(jìn)而來(lái)的,非設(shè)計(jì)出來(lái)的
 * @since JDK 8
 */
@Component
public class StockServiceFallback implements FallbackFactory<StockServiceFactory> {

    @Override
    public StockServiceFactory create(Throwable cause) {
        return new StockServiceFactory();
    }
}
/**
 * 錯(cuò)誤回調(diào)工廠(chǎng)類(lèi)
 */
class StockServiceFactory implements StockServiceProvider {
    /**
     * 方法描述: 調(diào)用stock服務(wù)的reduct接口的方法
     *
     * @return {@link String}
     * @author 魯浩鵬 Lu Haopeng
     * @date 2022/3/25 14:23
     */
    @Override
    public String reduce(int stockId) {
        return "庫(kù)存服務(wù)不可達(dá)";
    }
}
  • 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;

/**
 * 類(lèi)描述:
 *
 * @author 魯浩鵬 Lu Haopeng
 * @version 1.0
 * @email Lu Haopeng
 * @date 2022/4/5 16:02
 * @slogan 優(yōu)良的架構(gòu)是演進(jìn)而來(lái)的,非設(shè)計(jì)出來(lái)的
 * @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;

/**
 * 類(lèi)描述:
 *
 * @author 魯浩鵬 Lu Haopeng
 * @version 1.0
 * @email Lu Haopeng
 * @date 2022/4/5 16:22
 * @slogan 優(yōu)良的架構(gòu)是演進(jìn)而來(lái)的,非設(shè)計(jì)出來(lái)的
 * @since JDK 8
 */
public interface OrderMapper extends BaseMapper<JwsswOrder> {
}

五、庫(kù)存服務(wù)

  • StockController.java
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;

/**
 * 類(lèi)描述:對(duì)外提供服務(wù)類(lèi)
 *
 * @author 魯浩鵬 Lu Haopeng
 * @version 1.0
 * @email Lu Haopeng
 * @date 2022/3/19 10:46
 * @since JDK 8
 */
@RestController
@RequestMapping("/stock")
public class StockController {

    /** 獲取配置文件中的端口號(hào) */
    @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) {
    	// todo 為了演示方便寫(xiě)在此處了,正式項(xiàng)目中需要寫(xiě)在service中
        boolean update = stockService.lambdaUpdate().setSql("stock_number=stock_number -1")
                .eq(JwsswStock::getId, stockId).update();
        return update ? "扣減庫(kù)存成功" : "扣減庫(kù)存失敗";
    }
}

庫(kù)存的SQL語(yǔ)句

INSERT INTO `jwssw_stock` (`id`, `order_name`, `stock_number`) VALUES (1, '芬太尼', 77);
  • StockService.java
package com.jwssw.stock.service;

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

/**
 * 類(lèi)描述:
 *
 * @author 魯浩鵬 Lu Haopeng
 * @version 1.0
 * @email Lu Haopeng
 * @date 2022/4/5 18:32
 * @slogan 優(yōu)良的架構(gòu)是演進(jìn)而來(lái)的,非設(shè)計(jì)出來(lái)的
 * @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;

/**
 * 類(lèi)描述:
 *
 * @author 魯浩鵬 Lu Haopeng
 * @version 1.0
 * @email Lu Haopeng
 * @date 2022/4/5 18:33
 * @slogan 優(yōu)良的架構(gòu)是演進(jìn)而來(lái)的,非設(shè)計(jì)出來(lái)的
 * @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;

/**
 * 類(lèi)描述:
 *
 * @author 魯浩鵬 Lu Haopeng
 * @version 1.0
 * @email Lu Haopeng
 * @date 2022/4/5 18:32
 * @slogan 優(yōu)良的架構(gòu)是演進(jìn)而來(lái)的,非設(shè)計(jì)出來(lái)的
 * @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;

/**
 * 類(lèi)描述:
 *
 * @author 魯浩鵬 Lu Haopeng
 * @version 1.0
 * @email Lu Haopeng
 * @date 2022/4/5 18:30
 * @slogan 優(yōu)良的架構(gòu)是演進(jìn)而來(lái)的,非設(shè)計(jì)出來(lái)的
 * @since JDK 8
 */
@Data
@Builder
@TableName("jwssw_stock")
public class JwsswStock {
    private int id;
    private String orderName;
    private int stockNumber;
}

六、測(cè)試

單元測(cè)試類(lèi)是JUnti5

  • 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;

/**
 * 類(lèi)描述:?jiǎn)卧獪y(cè)試類(lèi)
 *
 * @author 魯浩鵬 Lu Haopeng
 * @version 1.0
 * @email Lu Haopeng
 * @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 {
        // 調(diào)用controller中的接口
        ResultActions resultActions = mvc.perform(get("/order/insert").param("num", "1"))
                .andDo(print())
                .andExpect(status().isOk());
       // 輸出結(jié)果
       System.out.println(resultActions.andReturn().getResponse().getContentAsString());
    }
}

小伙伴們自行運(yùn)行單元測(cè)試類(lèi)時(shí),需要修改num參數(shù)值(num=0是回滾)來(lái)實(shí)驗(yàn)seata分布式的回滾魅力。

原文鏈接:https://blog.csdn.net/lhp3000/article/details/124111987

欄目分類(lèi)
最近更新