nacos -注册中心
nacos是alibaba提供的管理微服务架构的注册中心,在上面可以管理你的每一个服务内容。
引入
前往官网下载zip或者通过docker引入,下载好之后通过cmd命令启动。位置在bin目录下。
startup.cmd -m standalone
这个命令的意思是通过单体项目启动nacos注册中心,启动之后可以看到你的nacos生成网址。
然后我们就需要在自己的项目中进行配置了,主项目需要引入下面这个包
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
让他们被发现nacos发现,然后在子model中,引入web包,让他们成为web服务。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
在子model中进行yml配置,通常nacos识别的服务名称就是你设置的applicationName。然后设置nacos服务地址为localhost:8848。
server:
port: 8000
spring:
application:
name: service-order
cloud:
nacos:
server-addr: 127.0.0.1:8848
config:
import-check:
enabled: false
这样你就可以在网址上看到你这个model的服务了。
之前必须要在启动类上加上注解@EnableDiscoveryClient才可以服务发现,但是从Spring Cloud Edgware开始,@EnableDiscoveryClient 或@EnableEurekaClient 可省略。只需加上相关依赖,并进行相应配置,即可将微服务注册到服务发现组件上。
使用代码获取每个服务信息
通过spring-cloud-nacos提供的discoveryClient接口来获取服务信息。
package com.atguigu.product;
import com.alibaba.cloud.nacos.discovery.NacosServiceDiscovery;
import com.alibaba.nacos.api.exception.NacosException;
import jakarta.annotation.Resource;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import java.util.List;
@SpringBootTest
public class DiscoveryTest {
@Resource
DiscoveryClient discoveryClient;
@Test
void discoveryTest(){
discoveryClient.getServices().forEach(service->{
List<ServiceInstance> instances = discoveryClient.getInstances(service);
instances.forEach(serviceInstance -> {
System.out.println("serviceInstance.getInstanceId() = " + serviceInstance.getInstanceId());
System.out.println("serviceInstance.getHost() = " + serviceInstance.getHost());
System.out.println("serviceInstance.getServiceId() = " + serviceInstance.getServiceId());
System.out.println("serviceInstance.getPort() = " + serviceInstance.getPort());
});
});
}
}
通过获取每个服务下的多个实例,并且将实例内容展示出来。
discoveryClient和nacosServiceDiscovery
就是spring和nacos提供的区别,如果使用的是前者discoveryClient,不管使用的是什么注册中心,都可以进行调用,而后者是引入nacos后才可以使用的接口。
@Resource
NacosServiceDiscovery nacosServiceDiscovery;
@Test
void discoveryTest() throws NacosException {
nacosServiceDiscovery.getServices().forEach(service->{
List<ServiceInstance> instances = null;
try {
instances = nacosServiceDiscovery.getInstances(service);
} catch (NacosException e) {
throw new RuntimeException(e);
}
instances.forEach(serviceInstance -> {
System.out.println("serviceInstance.getInstanceId() = " + serviceInstance.getInstanceId());
System.out.println("serviceInstance.getHost() = " + serviceInstance.getHost());
System.out.println("serviceInstance.getServiceId() = " + serviceInstance.getServiceId());
System.out.println("serviceInstance.getPort() = " + serviceInstance.getPort());
});
});
}
一样的,具体我就不多写了。
nacos实现远程调用
当我们服务去访问另一个服务的时候,通过nacos可以实现,我们通过获得服务实例,可以以负载均衡的方式,然后通过springboot提供的http请求api进行访问,拿到数据后返回给服务即可。
下面是一个生成订单的服务,需要去远程获取到商品信息,就可以通过下列方式实现。
package com.atguigu.order.service.impl;
import java.math.BigDecimal;
import java.util.Arrays;
import java.util.List;
import com.atguigu.order.bean.Order;
import com.atguigu.order.service.OrderService;
import com.atguigu.product.bean.Product;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.cloud.client.loadbalancer.LoadBalancerClient;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
@Slf4j
@Service
public class OrderServiceImpl implements OrderService {
@Autowired
DiscoveryClient discoveryClient;
@Resource
RestTemplate restTemplate;
@Override
public Order createOrder(Long productId, Long userId) {
// Product product = getProductFromRemoteWithLoadBalanceAnnotation(productId);
//使用Feign完成远程调用
Product product = getProFromRemote(productId);
Order order = new Order();
order.setId(1L);
// 总金额
order.setTotalAmount(product.getPrice().multiply(new BigDecimal(product.getNum())));
order.setUserId(userId);
order.setNickName("zhangsan");
order.setAddress("尚硅谷");
//远程查询商品列表
order.setProductList(Arrays.asList(product));
return order;
}
private Product getProFromRemote(Long proId){
List<ServiceInstance> instances = discoveryClient.getInstances("service-product");
ServiceInstance serviceInstance = instances.get(0);
String uri="http://"+serviceInstance.getHost()+":"+serviceInstance.getPort()+"/product/"+proId;
log.info("远程调用:{}",uri);
return restTemplate.getForObject(uri, Product.class);
}
}
上面的写法全部是访问第一个服务实例,那我们如何使用负载均衡的方式进行获取服务实例呢?
负载均衡方式
首先需要引入spring-cloud为我们提供的实现负载均衡api
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-loadbalancer</artifactId>
</dependency>
引入loadBalancerClient,使用方法choose即可实现负载均衡。
@Autowired
LoadBalancerClient loadBalancerClient;
private Product getProFromRemoteWithLoadBalance(Long proId){
ServiceInstance serviceInstance = loadBalancerClient.choose("service-product");
String uri="http://"+serviceInstance.getHost()+":"+serviceInstance.getPort()+"/product/"+proId;
log.info("远程调用以负载均衡的方式,实例为,{},uri:{}",serviceInstance.getInstanceId(),uri);
return restTemplate.getForObject(uri, Product.class);
}
通过注解方式实现负载均衡
使用 @LoadBalanced放到你要远程调用的实例上,然后通过将网址改成你要远程调用的实例就可以实现了。
private Product getProFromRemoteWithLoadBalanceAnnoation(Long proId){
String uri="http://servce-product/product/"+proId;
log.info("远程调用以负载均衡的方式,uri:{}",uri);
return restTemplate.getForObject(uri, Product.class);
}
}
nacos-配置中心
nacos核心是什么,就是将各个分开的服务进行统一管理,配置中心就是将服务的配置进行统一管理。
首先要引入依赖
<!--配置中心-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency
然后在nacos中创建一个配置文件。
通过spring提供的外部配置文件绑定属性,来和nacos创建的文件进行绑定。
spring:
application:
name: service-order
cloud:
nacos:
server-addr: 127.0.0.1:8848
config:
import-check:
enabled: false
config:
import: nacos:service-order.properties
然后就可以获取到里面内容并且进行操作了。
@Value("${order.timeout}")
private String timeout;
@Value("${order.auto-confirm}")
private String autoConfirm;
在这里有一点,如果你更改了nacos配置文件的内容,项目里并不会自动改变,只有重新启动或者配置了 @RefreshScope才可以刷新。
@RefreshScope写到使用配置文件内容的类上面
@RefreshScope//自动刷新
@RestController
public class OrderController {
@Autowired
OrderService orderService;
@Value("${order.timeout}")
private String timeout;
@Value("${order.auto-confirm}")
private String autoConfirm;
@GetMapping("/config")
public String config(){
return "autoConfirm = " + autoConfirm+",timeout="+timeout;
}
}
也可以用**@ConfigurationProperties**,这个直接有自动刷新方式。
package com.atguigu.order.properties;
import lombok.Data;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
@Configuration
@ConfigurationProperties(prefix = "order")
@Data
public class OrderProperties {
private String timeout;
private String autoConfirm;
}
也是更推荐这种方式,解耦更好。
配置中心监听
我们可以通过下列代码实现监听
@Bean
ApplicationRunner applicationRunner(NacosConfigManager nacosConfigManager) {
return (args) -> {
ConfigService configService = nacosConfigManager.getConfigService();
configService.addListener("service-order.properties",
"DEFAULT_GROUP", new Listener() {
//声明一个线程
@Override
public Executor getExecutor() {
return Executors.newFixedThreadPool(4);
}
@Override
public void receiveConfigInfo(String s) {
System.out.println("变化的配置信息:"+s);
System.out.println("邮件通知.........");
}
});
};
}
具体意思就是通过nacosConfigManager来获取配置服务类,通过配置服务类的添加监控方法,将需要监控的配置文件写到里面。
PS:配置中心的配置会覆盖本地配置,因为本地先配置中心后,不过为了统一配置,配置中心的配置应该才是优先级最高的配置。
配置中心-数据隔离
nacos可以通过设置命名空间来进行配置文件隔离。
设置完命名空间,你在创建配置文件的时候就可以把他们放到不同的 命名空间中,相当于一个文件夹,然后可以用配置文件的group来进行细分。
然后在项目yml中进行配置。
server:
port: 8000
spring:
application:
name: service-order
cloud:
nacos:
server-addr: 127.0.0.1:8848
config:
namespace: a44d4fc8-aee8-4f5f-ab40-85a0db6d0998
#这里的namespace写的是命名空间的id
config:
import:
- nacos:common.properties?group=order
- nacos:database.properties?group=order
要记住yml中配置的namespace是命名空间id,而不是名称。
OpenFeign
OpenFeign 是 Spring Cloud 生态中声明式的 HTTP 客户端框架,通过注解简化微服务间的远程调用。它基于原生 Feign 扩展,深度集成 SpringMVC 注解和负载均衡能力,使开发者能以调用本地方法的方式实现跨服务接口访问。
区别于编程式restTemplate,这个实现起来更加轻松。
使用
首先引入包
<!-- 声明式远程调用-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
然后在启动类上**@EnableFeignClients**注解启动feign
@SpringBootApplication
@EnableFeignClients //启动feign
public class OrderMainApplication {
创建一个feign接口,并且实现远程调用api。
package com.atguigu.order.feign;
import com.atguigu.product.bean.Product;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
@FeignClient(value = "service-product")
public interface ProductFeignClient {
@GetMapping("/product/{id}")
Product getOne(@PathVariable Long id);
}
spring会将带**@FeignClient的接口类里面的mvc格式接收头变为请求头,发送远程请求。
所以这个的意思就是去注册中心寻找service-product**的服务,获取到他的url,并拼接param,获取内容返回给使用方。
第三方api
也可以通过feign实现第三方请求,区别于自己的服务,需要在注解上多增加一个url,来告诉spring,这个是外部请求。
package com.atguigu.order.feign;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
@FeignClient(value = "service-weather",url = "http://t.weather.itboy.net/api/weather/city")
public interface WeatherFeignClient {
@GetMapping("/{cityId}")
public String weather(@PathVariable String cityId);
}
feign 日志
feign如果打开日志呢,只需要在配置类里面写上feignLogging的日志显示级别就行。
@Bean
Logger.Level feignLoggerLevel(){
return Logger.Level.FULL;
}
他还有NONE、BASIC、HEADERS。
分别是不显示内容。
显示请求方法和url和结果状态码和执行时间。
headers是显示basic的信息再加上request和response的headers。
full就是全有。
超时控制
如果feign请求的服务当机了,或者速度慢读取不到,我们都需要对feign进行一个超时控制。
对feign规定一个限时等待,如果超时就返回错误或者兜底数据,未超时就正常返回。
feign有一个默认设置。
连接时间10秒,等待时间60秒,那我们如何手动更改这些时间呢,其实就是更改options。
可以通过编码格式注入,也可以通过配置文件注入。
spring:
openfeign:
client:
config:
default:
connect-timeout: 1000
read-timeout: 2000
@Configuration
public class FeignConfiguration {
@Bean
public Request.Options options() {
return new Request.Options(8, TimeUnit.SECONDS, 8, TimeUnit.SECONDS, true);
}
但是一定是约定>配置>编码的,所以配置文件的优先级会更高一些。
拦截器
可以在feign上用拦截器加一层,请求拦截器和响应拦截器,用feign提供的RequestInterceptor就可以。
package com.atguigu.order.interceptor;
import feign.RequestInterceptor;
import feign.RequestTemplate;
import org.springframework.stereotype.Component;
import java.util.UUID;
@Component
public class XTokenRequestInterceptor implements RequestInterceptor {
@Override
public void apply(RequestTemplate requestTemplate) {
requestTemplate.header("token", UUID.randomUUID().toString());
}
}
那如何让spring知道这个拦截器呢,有两种方法,一种是直接将他放入容器中, feign每次都会从容器中读取requestInterceptor,或者使用配置文件。
spring:
openfeign:
client:
config:
service-product:
connect-timeout: 3000
read-timeout: 3000
request-interceptors:
- com.atguigu.order.interceptor.XTokenRequestInterceptor
兜底回调
就是如果没有获得本身内容,不返回给用户错误,而是一些假数据,让程序可以继续进行下去,也可以让用户体验好一些,那应该如何操作呢。需要使用sentinel来进行操作。
sentinel
Sentinel 是面向分布式服务架构的高可用流量防护组件,主要以流量为切入点,从限流、流量整形、熔断降级、系统负载保护、热点防护等多个维度来帮助开发者保障微服务的稳定性。
使用
首先下载sentinel的jar包,并且启动。
java -jar sentinel.jar
他默认占用8080端口,访问就可以看见sentinel的web页面。账号和密码都是sentinel。
如何让服务放入到里面呢,就是引入依赖,并且配置文件配置就行了,具体如下。
<!--sentinel-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
application.yml
spring:
sentinel:
transport:
dashboard: localhost:8080 #面板位置
eager: true #自动刷新
注入之后就可以看见他在里面显示出来了。
簇点链路
用户去访问资源的时候,如果这个资源配置了规则,sentinel就会去检查规则,如何符合则放行,如果不符合则抛出异常或者执行兜底回调。簇点链路就是sentinel在读取资源操作显示在页面上的链路操作,如下图。
下列配置就是将服务注册到sentinel中,可以被簇点链路获取。
spring.cloud.sentinel.transport.dashboard=localhost:8080
spring.cloud.sentinel.eager=true
eager是热加载,本身是要进行请求才会在sentinel中显示服务,将这个设置为true,可以直接出现。
异常处理
当我们给簇点链路设置规则之后,拦截的内容为sentinel为我们设定的,那我们如何自定义呢,这就要看我们如何设置得了。
根据下图,我们看到,如果是在浏览器端设置的,统一由BlockExceptionHandler来处理。
我们可以实现这个接口,自定义异常处理。
具体代码如下:
package com.atguigu.order.exception;
import com.alibaba.csp.sentinel.adapter.spring.webmvc_v6x.callback.BlockExceptionHandler;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.atguigu.common.R;
import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.stereotype.Component;
import java.io.PrintWriter;
@Component
public class MyBlockExceptionHandler implements BlockExceptionHandler {
ObjectMapper objectMapper = new ObjectMapper();
@Override
public void handle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, String s, BlockException e) throws Exception {
httpServletResponse.setContentType("application/json;charset=utf-8");
PrintWriter writer = httpServletResponse.getWriter();
R r = R.error(500, s + "流量超载,原因是" + e.getCause().getMessage());
String json = objectMapper.writeValueAsString(r);
writer.write(json);
}
}
@SentinelResource
一般是为非controller层设置的规则注解,设置之后可以被sentinel识别,继而可以配置规则,如果在这里出现规则限制,这去返回异常,异常可以被注解你的blockHandler包裹的方法解决,或者全局异常解决,具体如下。
@SentinelResource(value = "createOrder",blockHandler = "orderFallback")
public Order createOrder(Long productId, Long userId) {
// Product product = getProductFromRemoteWithLoadBalanceAnnotation(productId);
//使用Feign完成远程调用
Product product = productFeignClient.getProductById(productId);
Order order = new Order();
order.setId(1L);
// 总金额
order.setTotalAmount(product.getPrice().multiply(new BigDecimal(product.getNum())));
order.setUserId(userId);
order.setNickName("zhangsan");
order.setAddress("尚硅谷");
//远程查询商品列表
order.setProductList(Arrays.asList(product));
return order;
}
public Order orderFallback(Long productId, Long userId,BlockException e) {
return new Order();
}
剩下两个一个是openfeign远程调用,通过注解的fallback解决,一个是SphU,可以用来访问资源文件,通过try/cache解决。
规则-流浪控制
限制多余的请求,从而保护系统资源不被耗尽。
阙值类型
qps:统计每一秒的请求数
并发线程数:统计并发线程数
勾选是否集群,就可以选择单机阙值和总体阙值。
单机阙值就是每一个集群每秒可以访问的数量,总体阙值就是这几个集群一共可以访问的数量。
流控模式
流控模式可以选择3种模式,分别是直接、关联、链路。
直接策略就是上面的直接拦截,这里就不讲了。
链路策略:可以规定在在这个链路上的,访问量大的请求被拦截,就是更加灵活,不用直接拦截,只拦截请求量这个链路上请求量大的了。
关联策略:就是可以绑定另一个请求,当你在访问本请求时候,可以关联让另一个请求被拦截,这种可以用在数据校准度比较高的时候,在更改访问量大的时候,让访问的人少一些。
流控效果
流控效果有3个,快速失败、warm up、排队等待。
快速失败:就是当访问量超过阈值的时候,直接拦截失败。
warmup:我称之为慢慢起床,就是假如有10个请求,我们先走3个,过一会儿再走剩下的,这个数量是逐步递增的。
排队等待:就是字面意思,大家都排队,每次进来几个,然后有一个timeout,如果过了,剩下排队的请求都挂掉了。
sentinel具体内容可以查看官方文档。
gateway
gateway,相当于统一管理的后端的入口,你可以在后端入口进行拦截、保护、过滤等等请求。
使用
首先,使用gateway要引入依赖。
<dependencies>
<!--网关-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<!--服务发现-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<!--负载均衡-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-loadbalancer</artifactId>
</dependency>
</dependencies>
将gateway注册到nacos服务中,配置文件中进行nacos的配置。
然后在配置文件中,可以直接进行路由的配置。
server:
port: 80
spring:
application:
name: gateway
cloud:
nacos:
server-addr: 127.0.0.1:8848
gateway:
routes:
- id: order-route
uri: lb://service-order
predicates:
- Path=/api/order/**
- id: product-route
uri: lb://service-product
predicates:
- Path=/api/product/**
gateway默认优先级是顺序排列,如果你在第一个设置了非常大范围的Path,那么下面的内容就不会显示,可以使用order解决
gateway:
routes:
- id: order-bing
uri: https://cn.bing.com/
predicates:
- Path=/**
order: 10
predicates
断言,给路径可以设置规则。
predicates参数
自定义断言
如果我们想自定义断言,那应该如何进行呢。
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//
package org.springframework.cloud.gateway.handler.predicate;
import jakarta.validation.constraints.NotEmpty;
import java.util.Arrays;
import java.util.List;
import java.util.function.Predicate;
import org.springframework.util.StringUtils;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.server.ServerWebExchange;
public class QueryRoutePredicateFactory extends AbstractRoutePredicateFactory<Config> {
public static final String PARAM_KEY = "param";
public static final String REGEXP_KEY = "regexp";
public QueryRoutePredicateFactory() {
super(Config.class);
}
public List<String> shortcutFieldOrder() {
return Arrays.asList("param", "regexp");
}
public Predicate<ServerWebExchange> apply(final Config config) {
return new GatewayPredicate() {
public boolean test(ServerWebExchange exchange) {
if (!StringUtils.hasText(config.regexp)) {
return exchange.getRequest().getQueryParams().containsKey(config.param);
} else {
List<String> values = (List)exchange.getRequest().getQueryParams().get(config.param);
if (values == null) {
return false;
} else {
for(String value : values) {
if (value != null && value.matches(config.regexp)) {
return true;
}
}
return false;
}
}
}
public Object getConfig() {
return config;
}
public String toString() {
return String.format("Query: param=%s regexp=%s", config.getParam(), config.getRegexp());
}
};
}
@Validated
public static class Config {
private @NotEmpty String param;
private String regexp;
public String getParam() {
return this.param;
}
public Config setParam(String param) {
this.param = param;
return this;
}
public String getRegexp() {
return this.regexp;
}
public Config setRegexp(String regexp) {
this.regexp = regexp;
return this;
}
}
}
filter
过滤器允许以某种方式修改传入的HTTP请求或传出的HTTP响应。过滤器可以限定作用在某些特定请求路径上。 Spring Cloud Gateway包含许多内置的GatewayFilter工厂。
GatewayFilter工厂同上一篇介绍的Predicate工厂类似,都是在配置文件application.yml中配置,遵循了约定大于配置的思想,只需要在配置文件配置GatewayFilter Factory的名称,而不需要写全部的类名,比如AddRequestHeaderGatewayFilterFactory只需要在配置文件中写AddRequestHeader,而不是全部类名。在配置文件中配置的GatewayFilter Factory最终都会相应的过滤器工厂类处理。
server:
port: 8081
spring:
profiles:
active: add_request_header_route
---
spring:
cloud:
gateway:
routes:
- id: add_request_header_route
uri: http://httpbin.org:80/get
filters:
- AddRequestHeader=X-Request-Foo, Bar
predicates:
- After=2017-01-20T17:42:47.789-07:00[America/Denver]
profiles: add_request_header_route
cors
跨域问题可以通过gateway来解决
spring:
cloud:
gateway:
globalcors:
corsConfigurations:
'[/**]':
allow-credentials: true
allowedOrigins: "*"
allowedMethods: "*"
allowedHeaders: "*"
也可以通过meta进行单个的配置,不过一般不需要。
seata
分布式事务,用来解决分布式服务出现的数据不一致问题。
本身的服务是各自操作各自的,但我们在一个服务中通过openFeign去访问另一个服务的操作,并不会被本地的事务回滚。
seata拥有三个对象
1.TC transaction coordinator 事务协调者
2.TM transaction manager 事务管理器 全局事务
3.RM Resource manager 资源管理器
也就是当business开始这个服务的事务,会首先通知tc,tc给予一个全局事务,business去rpc访问其他服务,其他服务会创建分支事务,并且告诉tc,tc会知道所有服务的状态。
使用
首先安装seata
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-seata</artifactId>
</dependency>
使用注解**@GlobalTransaction**
seata使用二阶提交方式,首先每个服务先在本地进行操作,并且向tc申请全局锁,并且将前镜像和后镜像存储到undo_log当中,并将结果返回给tc。
第二阶段,tc根据返回的结果来进行回滚,回滚通过undo_log存储的数据,恢复到前镜像,并且这时候还会判断目前数据库的内容是否跟后镜像一样。
seata 四种事务模式
auto模式,全程有seata控制,从主事务到分支事务。
ax:全局锁是互斥锁。
tcc:具体实现要由程序员实现,prepare、commit、rollback
saga:结合消息队列,就是执行完成后,会通知下一个服务。
这就是基本使用的cloud了,完事。