目录


以一个父工程带两个Module(test1、test2)为例。
工程及sql脚本已经放入github:链接: https://github.com/fengjingju/springcloudtest

一、创建父工程

由于是模块化项目,那么父工程不需要实际的代码逻辑,因此无需创建src,那么可以有几种方式创建,例如:

  1. 使用Spring Initializr脚手架创建,构建工具选择Maven POM,即可创建出只带pom文件的Maven工程
  2. 使用脚手架或者只用maven创建后,删除src、.mvn目录

下面使用方式1来创建:
在这里插入图片描述
在这里插入图片描述
这里我们先不管SpringBoot的版本号,因为也没几个可选的合适的,创建完之后再改到合适的版本。默认3.0.3创建出来的java版本是17。不选择依赖
在这里插入图片描述
可以看到创建出来的父工程只有一个pom文件没有src目录
在这里插入图片描述

二、创建module模块

分别创建test1和test2模块。File–>new–>Module
在这里插入图片描述
依赖就勾一个Spring Web就行,剩下的慢慢补
在这里插入图片描述
创建之后的结构如下。展开模块 都带src文件夹和各自的pom文件
在这里插入图片描述 在这里插入图片描述

三、调整pom.xml

1、整改父pom与模块pom结构

在父pom中增加<packaging>pom</packaging>,代表父工程只作为整体项目的整合 传递依赖,在打包时不会生成jar/war包。pom中没有设置packaging时,默认使用jar打包
在这里插入图片描述
在父pom中增加<module>,module中的参数就是每个module中的artifactId
在这里插入图片描述
修改module pom中的parent信息,删除parent中的<relativePath>并删除自己的groupId。修改后的parent中parent信息均为父工程的pom参数,而父工程的parent为Spring原生的,形成了pom的层级传递关系
在这里插入图片描述

2、加入Spring Cloud依赖
首先需要确定版本号,Spring Cloud Alibaba、Spring Cloud、Spring Boot三者需要版本兼容
整体要以Spring Cloud Alibaba的版本为主,来决定SpringBoot的版本。

Spring Cloud Alibaba、Spring Cloud、Spring Boot官方版本说明地址:https://github.com/alibaba/spring-cloud-alibaba/wiki/%E7%89%88%E6%9C%AC%E8%AF%B4%E6%98%8E(此处如果打不开可能需要搬个梯子
在这里插入图片描述
目前企业中SpringBoot大部分使用Spring2.几,那么我们采用最新的稳定版2.3.12.RELEASE,Spring Cloud Alibaba采用2.2.9.RELEASE,那么Spring Cloud的版本就是Hoxton.SR12

修改父工程与子工程的java version为8,因为创建的时候用的Spring Boot 3.0.x,需要使用java 17,而改到2.x.x,就需要修改java版本。并在父pom中加入Spring Cloud Alibaba,Spring Cloud依赖(每个模块单独依赖也行,就是要写多个)
在这里插入图片描述
注意:Spring Cloud Alibaba和Spring Cloud都是使用import pom的方式在依赖中引入进来。默认的依赖scope为compile,type默认为jar,那么依赖的包就会在编译时将jar加载进来。而引入的jar过多会导致pom越来越大很难维护,于是可以定义一个父pom,通过import的方式继承过来,而把这部分相关的所有jar引用放到父pom里。其实直接定义<parent>也可以实现这样的继承,但是因为父工程已经继承了SpringBoot的pom,maven只能单继承,于是采用这样import的方式实现pom的多继承。

	<dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>Hoxton.SR12</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <dependency>
                <groupId>com.alibaba.cloud</groupId>
                <artifactId>spring-cloud-alibaba-dependencies</artifactId>
                <version>2.2.9.RELEASE</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

直接放到<dependencyManagement>中,dependencyManagement只声明依赖,原因下面引入nacos时讲
在这里插入图片描述

四、调整目录结构

由于直接用默认的maven,不需要使用maven wrapper,删除.mvn、mvnw、mvnw.cmd文件,HELP.md也删了吧,留着没什么用,需要可以后期补一个README.md。删完看效果(右图)
在这里插入图片描述 ------- 在这里插入图片描述

五、将服务注册到Nacos(注册中心)

1、安装Nacos

官网地址:https://nacos.io/zh-cn/index.html
在这里插入图片描述
在readme里面找到下载地址
在这里插入图片描述
或者直接看官网文档,也可以跳转到github下载链接
在这里插入图片描述
在这里插入图片描述

根据操作系统下载包,上面两个是安装包,下面两个是源码,windows直接下载nacos-server-2.2.0.zip即可
在这里插入图片描述

下载完之后,再看readme,里面告诉你启动方式,windows用cmd脚本启动,其实双击就行,但是因为默认的启动方式不是单机的,而是cluster集群模式。要么就是如下图一样在启动时后面跟上启动方式,要么直接修改脚本,将cluster修改为standalone
在这里插入图片描述
在这里插入图片描述

2、启动nacos

双击cmd脚本,如下图所示
在这里插入图片描述
然后在本地浏览器中输入URL:http://localhost:8848/nacos,账号密码:nacos/nacos,即可打开
在这里插入图片描述

3、项目中引入nacos

在父项目中引入nacos,由于是Spring Cloud Alibaba的starter,使用Spring Cloud Alibaba的版本:2.2.9.RELEASE
上面提到了,Spring Cloud的引入放在了dependencyManagement中,dependencyManagement只声明依赖,不发生实际的引入,管理公共版本号。而nacos的引入在单独的dependencies中,无需显示的写入版本号,则直接从dependencyManagement的com.alibaba.cloud中继承,也可手写覆盖默认版本号。

<dependency>
	<groupId>com.alibaba.cloud</groupId>
	<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>

在这里插入图片描述

4、配置 nacos

在test1模块的properties中配置nacos地址与服务名称

spring.application.name=test1
spring.cloud.nacos.discovery.server-addr=localhost:8848

启动test1服务,刷新nacos即可看到服务
在这里插入图片描述

六、nacos服务发现

继续新建一个module作为test1的消费端:test1-client
在test1中写如下方法:

@RestController
public class Hello {

    @RequestMapping("/hello")
    public String hello(){
        return "Hello World";
    }
}

使用test1-client去调用
没有注册中心的情况
我们直接去使用RestTemplate发生HTTP调用,RestTemplate不能直接AutoWried,需要写一个配置类,如下

@Configuration
public class RestTemplateConfig {

    @Bean
    public RestTemplate restTemplate(RestTemplateBuilder builder){
        return builder.build();
    }
}

然后调用

@RestController
public class Hello {

    @Autowired
    private RestTemplate restTemplate;

    @RequestMapping("hello-client")
    public String hello() {
        return restTemplate.getForObject("http://localhost:8080/hello", String.class);
    }
}

postman访问http://localhost:8081/hello-client,返回得到test1的hello方法值
在这里插入图片描述
由于注册中心的存在,我们每次不需要直接访问固定的IP+端口,而是使用预先在nacos中注册的服务名直接调用,如下,将http://localhost:8080/hello修改为http://test1/hello,使用test1的服务名代替IP+端口:

@RequestMapping("hello-client")
    public String hello() {
        return restTemplate.getForObject("http://test1/hello", String.class);
    }

同时restTemplate需要增加@LoadBalanced注解,具备负载均衡能力

@Bean
    @LoadBalanced
    public RestTemplate restTemplate(RestTemplateBuilder builder){
        return builder.build();
    }

测试OK
在这里插入图片描述

七、OpenFeign & Ribbon(HTTP)

简介

目前我们针对内部服务大多使用RPC,而针对外部服务仍然提供HTTP,那我们当做客户端去调用HTTP请求时,会用到以下技术:

Ribbon:是Netflix发布的开源项目,目前已停止维护,SpringCloud开发的LoadBalancer试图代替Ribbon,但目前负载均衡算法不足够,暂时无法代替。
Ribbon的诞生主要用于解决客户端负载均衡的问题。负载均衡一般包括客户端负载均衡服务器端负载均衡。例如Nginx为服务器端负载均衡,你把请求给我,我替你完成请求分发,相当于你不知道你要被分发到哪,完全由我来决定,这就是服务器端负载均衡;而客户端负载均衡通常会获取到服务方的地址,由自身算法来决定某个请求访问哪一台服务器。

Feign:也是Netflix发布的开源项目,目前已停止维护。而OpenFeign是SpringCloud自己研发的,在Feign的基础上支持了Spring MVC的注解,因此OpenFeign已经用于替代Feign。而Feign集成了Ribbon,且将Ribbon+RestTemplate请求的方式模板化,像调用本地方法那样更加优雅的完成开发。

目前来说Ribbon+RestTemplate、OpenFeign的方式均可,但个人更倾向于OpenFeign。

openfeign使用

创建openfeign的module,仍然作为test1的消费端
在这里插入图片描述
使用openfeign分为以下四步。

1、pom中引入openfeign的starter

		<dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>

2、消费方启动类新增@EnableFeignClients注解

@SpringBootApplication
@EnableFeignClients
public class Test1ClientOpenfeignApplication {

    public static void main(String[] args) {
        SpringApplication.run(Test1ClientOpenfeignApplication.class, args);
    }

}

3、标注客户端,指定要访问的nacos服务名

新建一个接口,使用@FeignClient注解标注,并指定要访问的nacos服务名;同时新建方法,其@RequestMapping路径与要访问的接口保持一致;若访问的服务类上面存在路径,则在@FeignClient中指定path

@FeignClient(name = "test1")
@Service
public interface FeignService {

    @RequestMapping("/hello")
    String hello();
}

4、开始调用

依赖注入刚刚定义的FeignService,并使用FeignService访问定义的方法,则会指向配置的服务及路径

@RestController
public class Hello {

    @Autowired
    private FeignService feignService;

    @RequestMapping("/hello-client")
    public String hello() {
        return feignService.hello();
    }
}

测试结果,该工程为8082端口,正确得到输出结果
在这里插入图片描述

八、Dubbo(RPC)

简介

当我们在内部服务之间调用时,可以RPC进行访问。

版本调整

由于Dubbo在Spring Cloud Alibaba 2021.0.1.0移出主干,那么想使用Spring Cloud中的Dubbo就需要降低版本。

原本是想将Spring Cloud Alibaba的版本号修改为2.2.7.RELEASE;相应的Spring
Cloud对应的版本号仍为Spring Cloud
Hoxton.SR12,相应的SpringBoot版本号仍为2.3.12.RELEASE。因此仅调整Spring Cloud
Alibaba版本号即可。 但实际发现,感觉是兼容性没做好还是怎么的,一直报错:An attempt was made to call a
method that does not exist. The attempt was made from the following …

那我们退而求其次降低一个版本:

Spring Cloud Alibaba:2.2.6.RELEASE
Spring Cloud:Hoxton.SR9 Spring
Boot:2.3.2.RELEASE

在这里插入图片描述

dubbo使用

dubbo作为RPC协议,需要服务方和消费方均遵循该协议,因此需要新建两个module,分别依赖Dubbo。

	<dependency>
        <groupId>com.alibaba.cloud</groupId>
        <artifactId>spring-cloud-starter-dubbo</artifactId>
    </dependency>

1、建立一个单独的工程,存放服务接口,供服务方与消费方实现与调用

首先要先建立一个公共业务api,一般都是单独放在一个工程里,并且消费方、服务方dubbo工程分别引入该api工程。如下,新建test3-dubbo-api工程,单独一个HelloService接口,一个hello()方法,并且入参出参的实体类必须实现序列化。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

2、新建服务方module:test3-server-dubbo,然后引入Dubbo、Nacos、test3-dubbo-api依赖

		<dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-dubbo</artifactId>
        </dependency>
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>
		<dependency>
            <groupId>com.example</groupId>
            <artifactId>test3-dubbo-api</artifactId>
            <version>0.0.1-SNAPSHOT</version>
        </dependency>

因为我的nacos在父工程pom中已经引入,这里不再进行单独依赖
在这里插入图片描述

a. @DubboService修饰类,暴露服务

新建服务方HelloServiceImpl,继承api中的HelloService并实现其方法
并使用注解@DubboService修饰类,将服务暴露

@DubboService
public class HelloServiceImpl implements HelloService {

    @Override
    public HelloResponse hello(HelloRequest request) {
        return new HelloResponse("hello world");
    }
}
b. 配置dubbo与nacos参数
spring.application.name=test3-server-dubbo
server.port=8090

# dubbo服务扫描路径(@DubboService修饰的类)
dubbo.scan.base-packages=com.example.test3serverdubbo
spring.cloud.nacos.discovery.server-addr=localhost:8848
dubbo.protocol.name=dubbo
# 服务端口,-1指不限制,也可使用其他数值指定
dubbo.protocol.port=-1
# 注册中心:使用当前技术栈的注册中心nacos
dubbo.registry.address=spring-cloud://localhost
c. 查看nacos服务已经起来了

在这里插入图片描述

3、新建消费方module:test3-client-dubbo,然后引入Dubbo、Nacos、test3-dubbo-api依赖(同上)

		<dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-dubbo</artifactId>
        </dependency>
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>
		<dependency>
            <groupId>com.example</groupId>
            <artifactId>test3-dubbo-api</artifactId>
            <version>0.0.1-SNAPSHOT</version>
        </dependency>

因为我的nacos在父工程pom中已经引入,这里不再进行单独依赖
在这里插入图片描述

a. 配置dubbo参数
spring.application.name=test3-client-dubbo
server.port=8091

dubbo.protocol.name=dubbo
## 服务端口,-1指不限制,也可使用其他数值指定
dubbo.protocol.port=-1
# 注册中心:使用当前技术栈的注册中心nacos
dubbo.registry.address=spring-cloud://localhost
# 需要调用的nacos服务名称
dubbo.cloud.subscribed-services=test3-server-dubbo
b. @DubboReference注解引用服务

然后新建Hello的Controller类,使用@DubboReference注解

@RestController
public class Hello {

    @DubboReference
    private HelloService helloService;

    @RequestMapping("/hello-client")
    public HelloResponse hello() {
        return helloService.hello(null);
    }
}

使用postman调用该接口,端口为8091,成功输出结果
在这里插入图片描述

九、Sentinel(降级、限流、熔断)

当我们存在服务A调用B,B调用C,即:A–>B–>C
雪崩效应:当C服务因某种原因不可用时,B的请求发出一直得不到响应,就持续占用B的线程,最终因为B的资源耗尽而导致B不可用,进而引发C的不可用,这样的现象称为雪崩效应。
一般处理高并发问题会采用如下方式:

  1. 降级:阉割服务功能,降低服务压力
  2. 设置超时时间:超过设置时间就自动释放线程,缓解服务压力
  3. 服务方限流:限制请求数在系统承受范围内,超出范围则直接报错
  4. 消费方熔断:

sentinel控制台

控制台git地址:https://github.com/alibaba/spring-cloud-alibaba/wiki/Sentinel
下载jar地址:https://github.com/alibaba/Sentinel/releases,看一下Spring Cloud Alibaba对应的Sentinel版本是1.8.1,翻到版本是v1.8.1的部分,展开Assets:
在这里插入图片描述
启动jar:直接java -jar就行,例如我的放在了D盘,启动后默认端口是8080。-Dserver.port=端口号可以用于修改端口号,其余设置参数可见官网(例如:用户名密码等)

java -jar D:\ComputerSoftware\sentinel-dashboard-1.8.1.jar

在这里插入图片描述
浏览器访问:http://127.0.0.1:8080/#/dashboard/home,用户名密码:sentinel / sentinel
在这里插入图片描述

Spring Cloud Alibaba引入Sentinel

1、添加依赖

pom中加入如下依赖,需要控制台可添加第二个依赖

		<dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
        </dependency>
        
        <!-- sentinel控制台 -->
        <dependency>
            <groupId>com.alibaba.csp</groupId>
            <artifactId>sentinel-transport-simple-http</artifactId>
        </dependency>

2、配置sentinel启动参数

支持两种方式:
1、可以启动java项目时指定启动参数,idea启动直接如下图配置即可

-Dcsp.sentinel.dashboard.server=127.0.0.1:8081

在这里插入图片描述
2、支持在配置文件中指定。如下图 设置端口号9090,服务名test2,sentinel为刚刚启动设置的8081端口

spring.application.name=test2
server.port=9090
spring.cloud.sentinel.transport.dashboard=127.0.0.1:8081

3、验证

然后再使用hello方法
在这里插入图片描述
postman调用9090端口
在这里插入图片描述
Sentinel控制台即可展示该服务,可以设置限流、熔断等。
在这里插入图片描述
设置2并发
在这里插入图片描述
然后使用jmeter跑10并发查看结果,验证OK,有一些失败的,并且失败原因为:flow limiting。至于成功的为什么不是只有2个请求而是4个,其实这个是随机的,一次性发出的十个并发和服务器设置的线程数相关,那么处理不完的线程就需要排队,轮到他的时候可能已经有成功的请求释放了令牌。
在这里插入图片描述

十、gateway(网关)

传统的项目都使用Nginx等负载均衡器来完成服务的路由功能,而在微服务中,由于服务数量的剧增,服务之间重复的问题尤其明显,例如:负载均衡、流量控制、黑白名单、容灾切换等。我们可以使用网关来完成这些功能。

当然网关也分很多种,例如:

  • 入口网关(Ingress Gateway):负责保护和控制来自集群外部的流量对集群的访问
  • 出口网关(Egress Gateway):负责控制离开集群的所有流量
  • 边车网关(Sidecar gateway):兼具以上两种功能只不过粒度更小,应用于服务网格,具体可百度

1、新建gateway的module,引入pom依赖

(记住不要同时引入web依赖,gateway与servlet冲突,会导致项目启动失败)

		<dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-gateway</artifactId>
        </dependency>

使用gateway来路由test1(http)、test3-server-dubbo(rpc)
在这里插入图片描述

2、打开路由开关,配置路由项

由于test3-server-dubbo是dubbo服务,因此配置dubbo协议开头,最后两行的意思是 使用gateway本身的路径加上/temp来代替test3-server-dubbo/HelloService,/temp后面加的路径 即为:test3-server-dubbo/HelloService后面加的,例如:/temp/hello,就代表:test3-server-dubbo/HelloService/hello
而为什么没有配置test1的,因为我们同时接入nacos,test1可以直接服务发现,不用在配置文件里单独配(test3-server-dubbo在nacos中也有,但不知道为什么不行,可能是因为协议问题),假如想访问test1的/hello路径就直接:http://gateway的IP+端口/test1/hello。test1的为http协议,能直接对接过去,test3-server-dubbo的需要在gateway中仍然使用dubbo来对接,这里不再赘述。

spring.application.name=gateway
server.port=9091

spring.cloud.gateway.discovery.locator.enabled=true

spring.cloud.gateway.routes[0].id=test1&test3-dubbo
spring.cloud.gateway.routes[0].uri=dubbo://test3-server-dubbo/HelloService
spring.cloud.gateway.routes[0].predicates[0]=Path=/temp/**

3、测试结果

在这里插入图片描述在这里插入图片描述

4、其他

gateway作为网关,除了路由还可以进行流量控制,因此可以整合sentinel来做限流熔断等,略。

十、分布式事务(Seata)

简介

当我们服务与服务之间发生调用关系且存在对数据的变更,那么就存在一个场景:任何一个环节出现问题,多个服务的数据必须全部回滚,才能保证数据的一致性。

例如现在我们实现一个:服务test1-client # insertUser方法 调用test1 # insertUser方法,存在如下步骤:

  1. test1-client # insertUser 往user_inf中插入一条数据:123,张三
  2. test1 # insertUser 往user_inf中插入一条数据:456,李四

这两个插入的数据要保证原子性,第一个user插入成功了再插入第二个,一旦第二个插入失败了 第一个也同时回滚,这就是分布式事务。

10.1 构造工程

a. 插入pom

		<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jdbc</artifactId>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.21</version>
        </dependency>

b. 新建数据库表

表名:user_inf,两个字段:user_id,user_name
在这里插入图片描述

c. 编写方法

test1(服务方),插入:456 李四

@RestController
public class Hello {

    @Autowired
    private JdbcTemplate jdbcTemplate;

    @RequestMapping("/insertUser")
    public String insertUser(){
        jdbcTemplate.execute("INSERT INTO user_inf (user_id,user_name) VALUES ('456','李四')");
        return "insert zhangsan & lisi success";
    }
}

test1-client(消费方),插入:123 张三;并调用test1,插入:456 李四

@RestController
public class UserController {

    @Autowired
    private RestTemplate restTemplate;

    @Autowired
    private JdbcTemplate jdbcTemplate;

    @RequestMapping("/insertUser")
    public String insertUser() {
        jdbcTemplate.execute("INSERT INTO user_inf (user_id,user_name) VALUES ('123','张三')");
        return restTemplate.getForObject("http://test1/insertUser", String.class);
    }
}

10.2 两条记录正常插入数据库效果

调用成功
在这里插入图片描述
DB里面已经成功插入张三和李四两条记录
在这里插入图片描述

10.3 单机事务

把数据库清空,这时候我们给test1的insertUser改造一下,加入一个异常,并且加入事务@Transactional,使其抛出异常数据插入发生回滚

@RequestMapping("/insertUser")
    @Transactional(rollbackFor = Exception.class)
    public String insertUser() throws Exception {
        jdbcTemplate.execute("INSERT INTO user_inf (user_id,user_name) VALUES ('456','李四')");
        throw new Exception("故意的exception");
//        return "insert zhangsan & lisi success";
    }

看效果
发生异常后,test1 # insertUser方法发生了事务回滚,但test1-client # insertUser仍然插入成功,数据库中仅存在123,张三的字样。原子性遭到破坏
在这里插入图片描述在这里插入图片描述

10.4 分布式事务

10.4.1 安装seata

a. 下载地址

官网下载:http://seata.io/zh-cn/blog/download.html,按照与Spring Cloud Alibaba对应的版本下载,我这里选择1.3.0

b. 修改配置文件

修改如下配置文件,高版本的seata的conf文件夹下没有nacos-config.txt,可以下载低版本的copy过来
在这里插入图片描述
nacos-config.txt
删除如下行:

service.vgroup_mapping.my_test_tx_group=default

添加刚刚的两个服务配置:
注意:spring cloud alibaba2.1以后的版本用这个

service.vgroupMapping.test1=default
service.vgroupMapping.test1-client=default

注意:spring cloud alibaba2.1以前的版本用这个

service.vgroup_mapping.test1=default
service.vgroup_mapping.test1-client=default
c. 将seata配置导入nacos

使用git执行nacos-config.sh如下命令。因为是shell脚本,要用git bash执行,路径记得先cd好或者写绝对路径

sh nacos-config.sh localhost

在这里插入图片描述
在这里插入图片描述
导入成功。会导入进去很多配置,翻到最后一页能看到这俩
在这里插入图片描述

d. 启动seata服务

在bin目录中,执行.bat文件。注意:jdk1.8以上无法启动

seata-server.bat -p 8090 -m file

启动成功
在这里插入图片描述
看nacos中已经有了seata服务
在这里插入图片描述

10.4.2 添加事务日志记录表

初始化数据库,在所有需要分布式事务的数据库中添加事务日志记录表
高版本这个sql脚本也没有,去低版本里找
在这里插入图片描述
在你使用的数据库中执行这个脚本的命令。其实就是新建一个undo_log的表
在这里插入图片描述

10.4.3配置Spring服务

a. 加入seata依赖
		<dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-seata</artifactId>
        </dependency>
b. 重写JdbcTemplate

使用Seata的重新包了一下。服务方和消费方都要重写!

@Configuration
public class JdbcTemplateConfig {

    @Bean
    public JdbcTemplate setJdbcTemplate(DataSource dataSource) {
        return new JdbcTemplate(new DataSourceProxy(dataSource));
    }
}

10.4.4 关联nacos中的seata服务

在application.properties中加入seata配置。服务方和消费方都要加入!
其中spring.application.name的配置必须与刚刚在seata中配置的nacos-config.txt结尾相同
在这里插入图片描述

spring.cloud.alibaba.seata.tx-service-group=${spring.application.name}

###################################  注意:只有Spring Cloud Alibaba 2.1之后版本要这样配 start ###############################
#################### Spring Cloud Alibaba 2.1之前的版本需要修改seata的registry.conf文件然后复制到工程中  ####################
### seata注册中心
# seata注册中心使用的服务
seata.registry.type=nacos
# nacos服务地址
seata.registry.nacos.server-addr=localhost:8848
# seata注册到nacos中的服务名
seata.registry.nacos.application=seata-server
seata.registry.nacos.username=nacos
seata.registry.nacos.password=nacos
seata.registry.nacos.group=SEATA_GROUP

### seata配置中心
seata.config.type=nacos
seata.config.nacos.server-addr=localhost:8848
seata.config.nacos.username=nacos
seata.config.nacos.password=nacos
seata.config.nacos.group=SEATA_GROUP
###################################  注意:只有Spring Cloud Alibaba 2.1之后版本要这样配 end ###############################
spring cloud alibaba2.1前的版本额外配置(spring cloud alibaba2.1之后的版本直接跳过)

spring cloud alibaba2.1前的版本需要修改conf目录中registry.conf文件内容,然后复制到工程的resource根目录下
在这里插入图片描述
registry.conf,保留以下配置,其他的直接删除

registry {
  # file 、nacos 、eureka、redis、zk、consul、etcd3、sofa
  type = "nacos"
  # seata注册中心
  nacos {
    application = "seata-server"
    serverAddr = "127.0.0.1:8848"
    namespace = "public"
    username = "nacos"
    password = "nacos"
  }
}

# seata配置中心
config {
  # file、nacos 、apollo、zk、consul、etcd3
  type = "nacos"

  nacos {
    serverAddr = "127.0.0.1:8848"
    namespace = "public"
    group = "SEATA_GROUP"
    username = "nacos"
    password = "nacos"
  }
}

把刚刚的registry.conf复制到Spring工程的resource根目录下
在这里插入图片描述

10.4.5 分布式事务使用及测试

直接在消费方的调用方法上增加如下注解即可生效。

@GlobalTransactional

test1-client

	@GlobalTransactional
    @RequestMapping("/insertUser")
    public String insertUser() {
        jdbcTemplate.execute("INSERT INTO user_inf (user_id,user_name) VALUES ('123','张三')");
        return restTemplate.getForObject("http://test1/insertUser", String.class);
    }

test1

	@RequestMapping("/insertUser")
    public String insertUser() throws Exception {
        jdbcTemplate.execute("INSERT INTO user_inf (user_id,user_name) VALUES ('456','李四')");
        throw new Exception("故意的exception");
//        return "insert zhangsan & lisi success";
    }

请求发生异常
在这里插入图片描述
查看,分布式事务生效!
user_inf表,未成功插入任何一条记录,而undo_log记录了两条,说明插入的两条数据均进行了回滚。
在这里插入图片描述

更多推荐