springcloud alibaba基础框架搭建学习笔记整理

39 篇文章 3 订阅
2 篇文章 0 订阅

单体微服务调用:

通过上面的调用图会发现,除了微服务,还有一个组件是服务注册中心,它是微服务架构非常重要

的一个组件,在微服务架构里主要起到了协调者的一个作用。注册中心一般包含如下几个功能:

1. 服务发现:

服务注册:保存服务提供者和服务调用者的信息

服务订阅:服务调用者订阅服务提供者的信息,注册中心向订阅者推送提供者的信息

2. 服务配置:

配置订阅:服务提供者和服务调用者订阅微服务相关的配置

配置下发:主动将配置推送给服务提供者和服务调用者

3. 服务健康检测

检测服务提供者的健康情况,如果发现异常,执行服务剔除

3.3.1 搭建nacos环境

第1步: 安装nacos

下载地址: https://github.com/alibaba/nacos/releases

下载zip格式的安装包,然后进行解压缩操作

第2步: 启动nacos

#切换目录

cd nacos/bin

#命令启动

startup.cmd -m standalone

第3步: 访问nacos

打开浏览器输入http://localhost:8848/nacos,即可访问服务, 默认密码是nacos/nacos

Feign 的入门使用

1、添加注解

<!--fegin组件--> <dependency>   <groupId>org.springframework.cloud</groupId>   <artifactId>spring-cloud-starter-openfeign</artifactId> </dependency>

2、在主类上添加Fegin的注解

@SpringBootApplication @EnableDiscoveryClient @EnableFeignClients//开启Fegin public class OrderApplication {}

3、 创建一个service, 并使用Fegin实现微服务调用,就是普通的 service服务

@FeignClient("service-product")//声明调用的提供者的name public interface ProductService {   //指定调用提供者的哪个方法   //@FeignClient+@GetMapping 就是一个完整的请求路径 http://service- product/product/{pid}   @RequestMapping(value = "/product/{pid}") //这里写法和springmvc的写法一样,   Product findByPid(@PathVariable("pid") Integer pid); }

4、修改controller代码,并启动验证

    //注入service服务 和本地调用一样 
    @Autowired 
    private ProductService productService; 
    @RequestMapping ("/order/prod/{pid}") 
    public Order order(@PathVariable("pid") Integer pid){ 
        log.info(" ========================= pid " + pid); 
        Product product = productService.findByPid(pid); 
        log.info(" ++++++++++++ product " + JSON.toJSONString(product)); 
        Order order = new Order(); 
        order.setPid(product.getPid()); 
        order.setUid(1); order.setUsername("测试用户"); 
        order.setPname(product.getPname()); order.setNumber(1); 
        orderService.createOrder(order); log.info(" ++++++++++++ order 添加成功 "); 
        return order; 
    }

5、测试返回数据

4.4.2 微服务集成Sentinel

1 在pom.xml中加入下面依赖

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

2 编写一个Controller测试使用

    @RequestMapping("/order/message1") 
    public String message1() { 
        return "message1"; 
    }
    @RequestMapping("/order/message2") 
    public String message2() { 
        return "message2"; 
    }

安装Sentinel控

进入到安装包的目录下

Sentinel 提供一个轻量级的控制台, 它提供机器发现、单机资源实时监控以及规则管理等功能。

1 、下载jar包,解压到文件夹

https://github.com/alibaba/Sentinel/releases

2 、启动控制台

# 直接使用jar命令启动项目(控制台本身是一个SpringBoot项目)

java -Dserver.port=8091 -Dcsp.sentinel.dashboard.server=localhost:8091 -Dproject.name=sentinel-dashboard -jar sentinel-dashboard-1.7.0.jar

启动成功,默认是懒加载的

将自己的服务对接到sentinel

 sentinel:   transport:    port: 9999 #跟控制台交流的端口,随意指定一个未使用的端口即可    dashboard: localhost:8080 # 指定控制台服务的地址

默认是懒加载的,需要访问一下自己的地址:例如 http://localhost:8091/order/message1

才能注册到sentinel服务,加载成功,如下图:

22、集视频观看:sentinel控制台

添加流控基本设置,每秒钟通过2个请求

浏览器疯狂刷新就可以看到了

最大线程限制,每秒最多通过2个线程

23、集视频观看:添加流控高级功能设置,默认是直接限流,下面讲解关联限流

对message2进行加压测试,当message2请求量超多设置值的时候,会对message1进行限流,

对message2进行加压测试,

测试message1就进行限流了

sentinel规则略过

31、集 sentinel的持久化设置

sentinel启动默认是存内存里面的,每次重启后都会失效,所以需求持久化存到文件里面,下次重启的时候可以读取文件自动使其生效

1、添加一个配置类

package com.itheima.config; import com.alibaba.csp.sentinel.command.handler.ModifyParamFlowRulesCommandHandler; import com.alibaba.csp.sentinel.datasource.*; import com.alibaba.csp.sentinel.init.InitFunc; import com.alibaba.csp.sentinel.slots.block.authority.AuthorityRule; import com.alibaba.csp.sentinel.slots.block.authority.AuthorityRuleManager; import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRule; import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRuleManager; import com.alibaba.csp.sentinel.slots.block.flow.FlowRule; import com.alibaba.csp.sentinel.slots.block.flow.FlowRuleManager; import com.alibaba.csp.sentinel.slots.block.flow.param.ParamFlowRule; import com.alibaba.csp.sentinel.slots.block.flow.param.ParamFlowRuleManager; import com.alibaba.csp.sentinel.slots.system.SystemRule; import com.alibaba.csp.sentinel.slots.system.SystemRuleManager; import com.alibaba.csp.sentinel.transport.util.WritableDataSourceRegistry; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.TypeReference; import org.springframework.beans.factory.annotation.Value; import java.io.File; import java.io.IOException; import java.util.List; /** * @Description: * @Param: * @param null * @return: * @Author: xlk * @Date: 2021/1/4 10:25 */ public class FilePersistence implements InitFunc { @Value("spring.application.name") private String appcationName; @Override public void init() throws Exception { String ruleDir = System.getProperty("user.home") + "/sentinel-rules/" + appcationName; String flowRulePath = ruleDir + "/flow-rule.json"; String degradeRulePath = ruleDir + "/degrade-rule.json"; String systemRulePath = ruleDir + "/system-rule.json"; String authorityRulePath = ruleDir + "/authority-rule.json"; String paramFlowRulePath = ruleDir + "/param-flow-rule.json"; this.mkdirIfNotExits(ruleDir); this.createFileIfNotExits(flowRulePath); this.createFileIfNotExits(degradeRulePath); this.createFileIfNotExits(systemRulePath); this.createFileIfNotExits(authorityRulePath); this.createFileIfNotExits(paramFlowRulePath); // 流控规则 ReadableDataSource<String, List<FlowRule>> flowRuleRDS = new FileRefreshableDataSource<>( flowRulePath, flowRuleListParser ); FlowRuleManager.register2Property(flowRuleRDS.getProperty()); WritableDataSource<List<FlowRule>> flowRuleWDS = new FileWritableDataSource<>( flowRulePath, this::encodeJson ); WritableDataSourceRegistry.registerFlowDataSource(flowRuleWDS); // 降级规则 ReadableDataSource<String, List<DegradeRule>> degradeRuleRDS = new FileRefreshableDataSource<>( degradeRulePath, degradeRuleListParser ); DegradeRuleManager.register2Property(degradeRuleRDS.getProperty()); WritableDataSource<List<DegradeRule>> degradeRuleWDS = new FileWritableDataSource<>( degradeRulePath, this::encodeJson ); WritableDataSourceRegistry.registerDegradeDataSource(degradeRuleWDS); // 系统规则 ReadableDataSource<String, List<SystemRule>> systemRuleRDS = new FileRefreshableDataSource<>( systemRulePath, systemRuleListParser ); SystemRuleManager.register2Property(systemRuleRDS.getProperty()); WritableDataSource<List<SystemRule>> systemRuleWDS = new FileWritableDataSource<>( systemRulePath, this::encodeJson ); WritableDataSourceRegistry.registerSystemDataSource(systemRuleWDS); // 授权规则 ReadableDataSource<String, List<AuthorityRule>> authorityRuleRDS = new FileRefreshableDataSource<>( authorityRulePath, authorityRuleListParser ); AuthorityRuleManager.register2Property(authorityRuleRDS.getProperty()); WritableDataSource<List<AuthorityRule>> authorityRuleWDS = new FileWritableDataSource<>( authorityRulePath, this::encodeJson ); WritableDataSourceRegistry.registerAuthorityDataSource(authorityRuleWDS); // 热点参数规则 ReadableDataSource<String, List<ParamFlowRule>> paramFlowRuleRDS = new FileRefreshableDataSource<>( paramFlowRulePath, paramFlowRuleListParser ); ParamFlowRuleManager.register2Property(paramFlowRuleRDS.getProperty()); WritableDataSource<List<ParamFlowRule>> paramFlowRuleWDS = new FileWritableDataSource<>( paramFlowRulePath, this::encodeJson ); ModifyParamFlowRulesCommandHandler.setWritableDataSource(paramFlowRuleWDS); } private Converter<String, List<FlowRule>> flowRuleListParser = source -> JSON.parseObject( source, new TypeReference<List<FlowRule>>() { } ); private Converter<String, List<DegradeRule>> degradeRuleListParser = source -> JSON.parseObject( source, new TypeReference<List<DegradeRule>>() { } ); private Converter<String, List<SystemRule>> systemRuleListParser = source -> JSON.parseObject( source, new TypeReference<List<SystemRule>>() { } ); private Converter<String, List<AuthorityRule>> authorityRuleListParser = source -> JSON.parseObject( source, new TypeReference<List<AuthorityRule>>() { } ); private Converter<String, List<ParamFlowRule>> paramFlowRuleListParser = source -> JSON.parseObject( source, new TypeReference<List<ParamFlowRule>>() { } ); private void mkdirIfNotExits(String filePath) throws IOException { File file = new File(filePath); if (!file.exists()) { file.mkdirs(); } } private void createFileIfNotExits(String filePath) throws IOException { File file = new File(filePath); if (!file.exists()) { file.createNewFile(); } } private <T> String encodeJson(T t) { return JSON.toJSONString(t); } }

2、添加一个配置文件,配置文件要求必须是这个名字 META-INF/services 而且必须在resource目录下,

3、然后添加文件这个文件 com.alibaba.csp.sentinel.init.InitFunc 这个文件必须必须必须这样写,不能修改,而且放到 META-INF/services 目录下

在这个com.alibaba.csp.sentinel.init.InitFunc文件里面填写 FilePersistence 这个文件 的全路径

经过测试使用,确实可以自动读取保存文件,自动使其生效

35集、SpringCloud Gateway介绍

Gateway 核心和网关执行流程

1、 基本概念

路由(Route) 是 gateway 中最基本的组件之一,表示一个具体的路由信息载体。主要定义了下面的几个信息:

id,路由标识符,区别于其他 Route。

uri,路由指向的目的地 uri,即客户端请求最终被转发到的微服务。

order,用于多个 Route 之间的排序,数值越小排序越靠前,匹配优先级越高。

predicate,断言的作用是进行条件判断,只有断言都返回真,才会真正的执行路由。

filter,过滤器用于修改请求和响应信息

2、执行流程

执行流程大体如下:

1. Gateway Client向Gateway Server发送请求

2. 请求首先会被HttpWebHandlerAdapter进行提取组装成网关上下文

3. 然后网关的上下文会传递到DispatcherHandler,它负责将请求分发给

RoutePredicateHandlerMapping

4. RoutePredicateHandlerMapping负责路由查找,并根据路由断言判断路由是否可用

5. 如果过断言成功,由FilteringWebHandler创建过滤器链并调用

6. 请求会一次经过PreFilter--微服务--PostFilter的方法,最终返回响应

40 集 Gateway自定义路由断言

自定义设置年龄的 - Age=18,60 # 限制年龄只有在18到60岁之间的人能访问

server: port: 7000 spring: application: name: api-gateway cloud: nacos: discovery: server-addr: 127.0.0.1:8848 #添加nacos的服务地址 gateway: discovery: locator: enabled: true # 让gateway可以发现nacos中的微服务 routes: # 路由数组[路由 就是指定当请求满足什么条件的时候转到哪个微服务] - id: product_route # 当前路由的标识, 要求唯一 # uri: http://localhost:8081 # 请求要转发到的地址 uri: lb://service-product # lb指的是从nacos中按照名称获取微服务,并遵循负载均衡策略 order: 1 #路由的优先级,数字越小代表路由的优先级越高 predicates: # 断言(就是路由转发要满足的条件) - Path=/product-serv/** # 当请求路径满足Path指定的规则时,才进行路由转发 测试访问: http://localhost:7000/product-serv/product/1 - Age=18,60 # 限制年龄只有在18到60岁之间的人能访问 filters: # 过滤器,请求在传递过程中可以通过过滤器对其进行一定的修改 - StripPrefix=1 # 转发之前去掉1层路径

这个类不能随意命名,有固定格式,如下,配置文件的名字后面拼接 RoutePredicateFactory 就是所起java类名字

自定义一个断言工厂, 实现断言方法

package com.itheima.predicates; import org.apache.commons.lang3.StringUtils; import org.springframework.cloud.gateway.handler.predicate.AbstractRoutePredicateFactory; import org.springframework.stereotype.Component; import org.springframework.web.server.ServerWebExchange; import java.util.Arrays; import java.util.List; import java.util.function.Predicate; //这是一个自定义的路由断言工厂类,要求有两个 //1 名字必须是 配置+RoutePredicateFactory //2 必须继承AbstractRoutePredicateFactory<配置类> @Component public class AgeRoutePredicateFactory extends AbstractRoutePredicateFactory<AgeRoutePredicateFactory.Config> { //构造函数 public AgeRoutePredicateFactory() { super(AgeRoutePredicateFactory.Config.class); } //读取配置文件的中参数值 给他赋值到配置类中的属性上 public List<String> shortcutFieldOrder() { //这个位置的顺序必须跟配置文件中的值的顺序对应 return Arrays.asList("minAge", "maxAge"); } //断言逻辑 public Predicate<ServerWebExchange> apply(AgeRoutePredicateFactory.Config config) { return new Predicate<ServerWebExchange>() { @Override public boolean test(ServerWebExchange serverWebExchange) { //1 接收前台传入的age参数 String ageStr = serverWebExchange.getRequest().getQueryParams().getFirst("age"); //2 先判断是否为空 if (StringUtils.isNotEmpty(ageStr)) { //3 如果不为空,再进行路由逻辑判断 int age = Integer.parseInt(ageStr); if (age < config.getMaxAge() && age > config.getMinAge()) { return true; } else { return false; } } return false; } }; } //配置类,用于接收配置文件中的对应参数 // @Data // @NoArgsConstructor public static class Config { private int minAge;//18 private int maxAge;//60 public Config() { } public int getMinAge() { return minAge; } public void setMinAge(int minAge) { this.minAge = minAge; } public int getMaxAge() { return maxAge; } public void setMaxAge(int maxAge) { this.maxAge = maxAge; } } }

测试,启动 product 和 apiFataway服务

#测试发现当age在(20,60)可以访问,其它范围不能访问

http://localhost:7000/product-serv/product/1?age=30

http://localhost:7000/product-serv/product/1?age=10

访问成功

访问失败

自定义一个全局过滤器

第一步 创建java类 AuthGlobalFilter ,命名规则 : 什么什么 + GlobalFilter ,然后继承 GlobalFilter, Ordered

package com.itheima.filter; import org.apache.commons.lang3.StringUtils; import org.springframework.cloud.gateway.filter.GatewayFilterChain; import org.springframework.cloud.gateway.filter.GlobalFilter; import org.springframework.core.Ordered; import org.springframework.http.HttpStatus; import org.springframework.stereotype.Component; import org.springframework.web.server.ServerWebExchange; import reactor.core.publisher.Mono; /** * @program: spring-cloud-alibaba * @author: xlk * @create: 2021-01-07 11:50 */ //全局过滤器 @Component public class AuthGlobalFilter implements GlobalFilter, Ordered { //自定义完成判断逻辑 @Override public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) { String token = exchange.getRequest().getQueryParams().getFirst("token"); if(!StringUtils.equals(token,"admin")){ System.out.println(" 认证失败 。。。。"); exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED); return exchange.getResponse().setComplete(); } return chain.filter(exchange); } //顺序,数值越小,优先级越高 @Override public int getOrder() { return 0; } }

第二步:测试

不加 token

直接访问测试,报错返回所填状态码 401

添加所需 : token

Sleuth入门

添加maven依赖

<!-- 注意这里要放到 dependencyManagement 外面,新建一个 dependencies--> <dependencies> <!--链路追踪 Sleuth--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-sleuth</artifactId> </dependency> </dependencies>

控制台会打印一些日志

微服务名称, traceId, spanid,是否将链路的追踪结果输出到第三方平台

[service-product,6bc973bfbc1891b9,85acaa27ddca1a5b,false]

[service-order,6bc973bfbc1891b9,6bc973bfbc1891b9,false]

[api-gateway,6bc973bfbc1891b9,68433228b280e03d,false]

其中 5399d5cb061971bd 是TraceId, 5399d5cb061971bd 是SpanId,依次调用有一个全局的TraceId,将调用链路串起来。仔细分析每个微服务的日志,不难看出请求的具体过程。

查看日志文件并不是一个很好的方法,当微服务越来越多日志文件也会越来越多,通过Zipkin可以将日志聚合,并进行可视化展示和全文检索。

Zipkin的集成

下载地址:https://search.maven.org/remote_content?g=io.zipkin.java&a=zipkin-server&v=LATEST&c=exec

通过浏览器访问

进入到ZipKin 包的地址

java -jar zipkin-server-2.12.9-exec.jar

集成,添加maven的依赖

<!--在每个微服务上添加依赖--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-zipkin</artifactId> </dependency>

在application.yml添加配置,每个application.yml都需要配置

zipkin: base-url: http://127.0.0.1:9411/ #zipkin server的请求地址 discoveryClientEnabled: false #让nacos把它当成一个URL,而不要当做服务名 sleuth: sampler: probability: 1.0 #采样的百分比

控制台打印,这里为true,说明向Zipkin导出数据了

UI界面展示

ZipKin数据持久化 mysql

建表语句,官方提供

CREATE TABLE IF NOT EXISTS zipkin_spans ( `trace_id_high` BIGINT NOT NULL DEFAULT 0 COMMENT 'If non zero, this means the trace uses 128 bit traceIds instead of 64 bit', `trace_id` BIGINT NOT NULL, `id` BIGINT NOT NULL, `name` VARCHAR(255) NOT NULL, `parent_id` BIGINT, `debug` BIT(1), `start_ts` BIGINT COMMENT 'Span.timestamp(): epoch micros used for endTs query and to implement TTL', `duration` BIGINT COMMENT 'Span.duration(): micros used for minDuration and maxDuration query' ) ENGINE=InnoDB ROW_FORMAT=COMPRESSED CHARACTER SET=utf8 COLLATE utf8_general_ci; ALTER TABLE zipkin_spans ADD UNIQUE KEY(`trace_id_high`, `trace_id`, `id`) COMMENT 'ignore insert on duplicate'; ALTER TABLE zipkin_spans ADD INDEX(`trace_id_high`, `trace_id`, `id`) COMMENT 'for joining with zipkin_annotations'; ALTER TABLE zipkin_spans ADD INDEX(`trace_id_high`, `trace_id`) COMMENT 'for getTracesByIds'; ALTER TABLE zipkin_spans ADD INDEX(`name`) COMMENT 'for getTraces and getSpanNames'; ALTER TABLE zipkin_spans ADD INDEX(`start_ts`) COMMENT 'for getTraces ordering and range'; CREATE TABLE IF NOT EXISTS zipkin_annotations ( `trace_id_high` BIGINT NOT NULL DEFAULT 0 COMMENT 'If non zero, this means the trace uses 128 bit traceIds instead of 64 bit', `trace_id` BIGINT NOT NULL COMMENT 'coincides with zipkin_spans.trace_id', `span_id` BIGINT NOT NULL COMMENT 'coincides with zipkin_spans.id', `a_key` VARCHAR(255) NOT NULL COMMENT 'BinaryAnnotation.key or Annotation.value if type == -1', `a_value` BLOB COMMENT 'BinaryAnnotation.value(), which must be smaller than 64KB', `a_type` INT NOT NULL COMMENT 'BinaryAnnotation.type() or -1 if Annotation', `a_timestamp` BIGINT COMMENT 'Used to implement TTL; Annotation.timestamp or zipkin_spans.timestamp', `endpoint_ipv4` INT COMMENT 'Null when Binary/Annotation.endpoint is null', `endpoint_ipv6` BINARY(16) COMMENT 'Null when Binary/Annotation.endpoint is null, or no IPv6 address', `endpoint_port` SMALLINT COMMENT 'Null when Binary/Annotation.endpoint is null', `endpoint_service_name` VARCHAR(255) COMMENT 'Null when Binary/Annotation.endpoint is null' ) ENGINE=InnoDB ROW_FORMAT=COMPRESSED CHARACTER SET=utf8 COLLATE utf8_general_ci; ALTER TABLE zipkin_annotations ADD UNIQUE KEY(`trace_id_high`, `trace_id`, `span_id`, `a_key`, `a_timestamp`) COMMENT 'Ignore insert on duplicate'; ALTER TABLE zipkin_annotations ADD INDEX(`trace_id_high`, `trace_id`, `span_id`) COMMENT 'for joining with zipkin_spans'; ALTER TABLE zipkin_annotations ADD INDEX(`trace_id_high`, `trace_id`) COMMENT 'for getTraces/ByIds'; ALTER TABLE zipkin_annotations ADD INDEX(`endpoint_service_name`) COMMENT 'for getTraces and getServiceNames'; ALTER TABLE zipkin_annotations ADD INDEX(`a_type`) COMMENT 'for getTraces'; ALTER TABLE zipkin_annotations ADD INDEX(`a_key`) COMMENT 'for getTraces'; ALTER TABLE zipkin_annotations ADD INDEX(`trace_id`, `span_id`, `a_key`) COMMENT 'for dependencies job'; CREATE TABLE IF NOT EXISTS zipkin_dependencies ( `day` DATE NOT NULL, `parent` VARCHAR(255) NOT NULL, `child` VARCHAR(255) NOT NULL, `call_count` BIGINT ) ENGINE=InnoDB ROW_FORMAT=COMPRESSED CHARACTER SET=utf8 COLLATE utf8_general_ci; ALTER TABLE zipkin_dependencies ADD UNIQUE KEY(`day`, `parent`, `child`);

在启动ZipKin Server的时候,指定数据保存的mysql的信息

java -jar zipkin-server-2.12.9-exec.jar --STORAGE_TYPE=mysql -- MYSQL_HOST=127.0.0.1 --MYSQL_TCP_PORT=3306 --MYSQL_DB=zipkin --MYSQL_USER=root - -MYSQL_PASS=root

测试RocketMQ

参考地址: rocketmq安装启动

进入目录文件夹 : cd /usr/local/rocketmq/rocketmq-all-4.4.0-bin-release/bin

设置一个路径:export NAMESRV_ADDR=localhost:9876

发送命令: bin/tools.sh org.apache.rocketmq.example.quickstart.Producer

接受命令

进入目录文件夹 : cd /usr/local/rocketmq/rocketmq-all-4.4.0-bin-release/bin

设置一个路径: export NAMESRV_ADDR=localhost:9876

接受命令: bin/tools.sh org.apache.rocketmq.example.quickstart.Consumer

5、分布式事务 seata-server-0.9.0

解压seata-server-0.9.0文件,需要修改两个配置文件

修改配置文件 registry.conf

registry {  type = "nacos"  nacos {    serverAddr = "localhost"    namespace = "public"    cluster = "default"  } } config {  type = "nacos"  nacos {    serverAddr = "localhost"    namespace = "public"    cluster = "default"  } }

修改配置文件 nacos-config.txt

# 初始化seata 的nacos配置

# 注意: 这里要保证nacos是已经正常运行的

进入conf文件下执行cmd命令

执行命令

nacos-config.sh 127.0.0.1

如果cmd不能启动,就使用Git Bash Here命令启动,启动命令

./nacos-config.sh 127.0.0.1

执行脚本

成功后去nacos的ui界面查看

如下图所示说明启动成功

开始启动seata服务

启动 命令,进入到bin目录下

cmd 命令执行

seata-server.bat -p 9000 -m file

去nacos查看,如下图说明启动成功

在我们的数据库中加入一张undo_log表,这是Seata记录事务日志要用到的表

作用是用户异常回滚

添加日志记录表sql语句

CREATE TABLE `undo_log` ( `id` bigint(20) NOT NULL AUTO_INCREMENT, `branch_id` bigint(20) NOT NULL, `xid` varchar(100) NOT NULL, `context` varchar(128) NOT NULL, `rollback_info` longblob NOT NULL, `log_status` int(11) NOT NULL, `log_created` datetime NOT NULL, `log_modified` datetime NOT NULL, `ext` varchar(100) DEFAULT NULL, PRIMARY KEY (`id`), UNIQUE KEY `ux_undo_log` (`xid`,`branch_id`) ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值