LLLLLuuusa的个人博客 - 微服务
type: channel
link: https://www.llllluuusa.top/index.php/tag/%E5%BE%AE%E6%9C%8D%E5%8A%A1/
items: Redisson
items: elesticsearch
items: 微服务笔记
items: sentinel
items: 任务调度
items: 多级缓存
items: securityOuth2
items: seata

Redisson
type: item
date: 2025-07-18T21:37:08+08:00
description: 介绍Redisson是一个在Redis的基础上实现的Java驻内存数据网格（In-Memory Data Grid）。它不仅提供了一系列的分布式的Java常用对象，还提供了许多分布式服务。Redisson的宗旨是促进使用者对Redis的关注分离（Separation of Concern），从而让使用者能够将精力更集中地放在处理业务逻辑上简而言之就是避免多个线程操作同个数据时发生数据不一致问题传统解决方法使用锁的方案可确保当一个线程在运行时,没有其他线程干扰,以下是常用的锁类型: 互斥锁 快速反馈锁 读写锁 Synchronized使用互斥锁,以确保同一时刻只有一个线程能够反复进入同步块java synchronized(this) { //执行逻辑... } 如果锁没有被其他线程占用，那么当前线程会获得锁并进入同步代码块或方法。 如果锁已经被其他线程占用，那么当前线程将进入等待状态，直到锁被释放。其他线程在释放锁后，等待队列中的线程将有机会竞争获取锁。 问题: 死锁：如果多个线程互相持有不同的锁，并且互相等待对方释放锁，就会发生死锁，导致所有线程都无法继续执行。 饥饿：某些线程可能会因为竞争较激烈，一直无法获得锁，从而导致饥饿现象，即某些线程无法得到执行的机会。 LockReentrantLocksynchronized的升级版,使用快速反馈锁,可对某个线程进行保护,直到该线程被解锁之前,其他线程无法进入,但被保护的线程可反复进入```java private Lock lock = new ReentrantLock();public void performTask() { lock.lock(); // 上锁 try { //执行逻辑 } finally { lock.unlock(); // 解锁 } } ```ReentrantLock区别与synchronized是当其他线程进了的时候,可以选择线程等待或是执行其他逻辑```java private Lock lock = new ReentrantLock();public void performTask() { if (lock.tryLock(3, TimeUnit.SECONDS)) {// 上锁,设置等待时间 try { //执行逻辑A } finally { lock.unlock(); // 解锁 } }else { //执行逻辑B } } ```ReentrantReadWriteLock和ReentrantReadWriteLock使用读写锁，它允许多个线程同时读取共享资源，但只允许一个线程写入共享资源。这在读多写少的情况下可以提高并发性能，因为多个线程可以同时读取资源，而写操作需要互斥```java private Lock lock = new ReentrantLock();public int readData() { readWriteLock.readLock().lock(); try { // 读取数据 return data; } finally { readWriteLock.readLock().unlock(); } }public void writeData(int newData) { readWriteLock.writeLock().lock(); // Acquire write lock try { // 写入数据 data = newData; } finally { readWriteLock.writeLock().unlock(); } } ```Redis分布式锁使用SETNX实现分布式锁powershell setnx key valye若key的值不存在,则执行set key value,若存在则不做任何操作```java String clientId = UUID.randomUUID().toString();Boolean success = redisTemplate.opsForValue().setIfAbsent("key", "locked",10,TimeUnit.SECONDS); try{ //执行逻辑 }finally{ if(clientId.equals(redisTemplate.opsForValue().get("key"))) redisTemplate.delete("key"); } ```Redssion分布式锁synchronized和Lock无法对分布式项目进行线程保护,因为传统方案使用的锁是JVM锁Redis分布式锁如果线程执行较长,key过期了线程还未结束,就出现操作同一数据问题Redssion对Redis分布式锁进行了封装,并使用定时任务,…

elesticsearch
type: item
date: 2025-07-18T21:37:08+08:00
description: 初识MQ同步和异步通讯 同步通讯 微服务直接的直接调用就属于同步通讯优点:​ 时效性强,可立即得到结果缺点: 耦合性高​ 性能和吞吐能力低​ 有额外的资源消耗​ 有级联失效问题常用场景: 需要即可得到结果的服务之间使用同步通讯​ 异步通讯 异步通讯使用一个中间件Broker,当某个服务想要发起请求时,直接向Broker发起事件,然后继续执行自己的代码.Broker接收到事件后,会向其他服务发起调用,若该服务处于繁忙或宕机,则缓存等待后再发起.优点:​ 耦合度低​ 吞吐量提升​ 故障隔离​ 流量削峰缺点:​ 依赖于Broker的可靠性、安全性、吞吐能力​ 架构复杂,业务没有明显流程,不方便追钟问题MQ常见技术RabbitMQ概述和安装docker拉取镜像tex docker pull rabbitmq:3-management运行rabbitmq```text docker run \ -e RABBITMQ_DEFAULT_USER=用户名 \ -e RABBITMQ_DEFAULT_PASS=密码 \ -v mq-plugins:/plugins \ --name mq \ --hostname mq1 \ -p 15672:15672 \ -p 5672:5672 \ -d \ 镜像id```rabbit有两个端口,15672是管理员端口,从web可进入管理员页面,5672是用户端口,可从该端口使用rabbitmq消息模型rabbitMQ官方提供了6种消息模型,实际能用的有5种 基础队列模型 工作消息队列 广播 路由 主题 入门案例该入门案例使用的是官方的rabbitmq提供的连接方式,了解即可,后面使用spring提供的AMQP快捷连接导入依赖xml <dependency> <groupId>com.rabbitmq</groupId> <artifactId>amqp-client</artifactId> <version>3.0.4</version> </dependency>发送端```java // 1.建立连接 ConnectionFactory factory = new ConnectionFactory(); // 1.1设置连接参数,分别是:主机Ip、端口、vhost、用户名、密码 factory.setHost("主机IP"); factory.setPort(端口); factory.setVirtualHost("vhost"); factory.setUsername("用户名"); factory.setPassword("密码"); // 1.2建立连接 connection = factory.newConnection();// 2.创建通道 channel = connection.createChannel();// 3.创建队列 String queueName = "队列名"; channel.queueDeclare(queue, false, false, false, null);// 4.发送消息 String message = "hello,rabbitMQ"; channel.basicPublish("",queueName,null,message.getBytes());// 5.关闭通道和连接 channel.close(); connection.close(); ```接收端```java // 1.建立连接 ConnectionFactory factory = new ConnectionFactory(); // 1.1设置连接参数,分别是:主机Ip、端口、vhost、用户名、密码 factory.setHost("主机IP"); factory.setPort(端口); factory.setVirtualHost("vhost"); factory.setUsername("用户名"); factory.setPassword("密码"); // 1.2建立连接 connection = factory.newConnection();// 2.创建通道 channel = connection.createChannel();// 3.创建队列 String queueName = "队列名"; channel.queueDeclare(queue, false, false, false, null);// 4.订阅消息 channel.basicConsume(queueName,true,new DefaultConsumer(channel){ @Override public void handleDelivery(Strin…

微服务笔记
type: item
date: 2025-07-18T21:37:08+08:00
description: 微服务介绍单体架构单体式架构将所有服务放在同一个项目 部署简单 耦合性高 分布式架构分布式价格将多种服务拆分到不同项目 部署麻烦 耦合性低 高可用 集群部署困难 微服务的分布式架构微服务的分布式在原有的分布式架构上进行改良,解决了传统分布式中部署和集群等问题常见的分布式技术Spring Cloud项目结构在微服务项目中,不同的功能应放在不同的项目里远程调用不同的服务之间数据需要通信时,由于各服务已经暴露了接口位置,所以当A服务想要使用B服务的功能时,可使用http通信方式调用HttpUtil这是比较传统Http通信,需要自行创建HttpUtil,再调用```java public class HttpUtil { private static String USER_AGENT = "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.0; Trident/4.0; SLCC1; .NET CLR 2.0.50727; .NET CLR 3.0.04506; customie8)";// HTTP GET request public static String sendGet(String url, String charset) throws Exception { URL realurl = new URL(url); HttpURLConnection con = (HttpURLConnection) realurl.openConnection(); // optional default is GET con.setRequestMethod("GET"); // add request header con.setRequestProperty("User-Agent", USER_AGENT); // int responseCode = con.getResponseCode(); // System.out.println("Response Code : " + responseCode); BufferedReader in = new BufferedReader(new InputStreamReader(con.getInputStream(), charset)); String inputLine; StringBuffer result = new StringBuffer(); while ((inputLine = in.readLine()) != null) { result.append(inputLine); result.append("\r\n"); } in.close(); con.disconnect(); return result.toString(); } // HTTP POST request @SuppressWarnings("deprecation") public static String sendPost(String url, Map<String, String> param, String charset) throws Exception { URL realurl = new URL(url); HttpsURLConnection con = (HttpsURLConnection) realurl.openConnection(); con.setRequestMethod("POST"); // add reuqest header con.setRequestProperty("User-Agent", USER_AGENT); // con.setRequestProperty("Accept-Language", "en-US,en;q=0.5"); // String urlParameters = // "sn=C02G8416DRJM&cn=&locale=&caller=&num=12345"; StringBuffer buffer = new StringBuffer(); if (param != null && !param.isEmpty()) { for (Map.Entry<String, String> entry : param.entrySet()) { buffer.append(entry.getKey()).append("=").append(URLEncoder.encode(entry.getValue(), charset)) .append("&"); } } buffer.deleteCharAt(buffer.length() - 1…

elesticsearch
type: item
date: 2025-07-18T21:37:08+08:00
description: 认识Elasitcsearch一个开源的分布式搜索引擎,可以用来实现搜索、日志统计、分析、系统监控等Elesticsearch核心技术就是倒排索引倒排索引和正向索引正向索引传统数据库如Mysql就是使用正向索引 根据ID搜索数据,数据库就会使用B+树来进行快速查询但如果是查询词条,就没有ID,而是逐行查询,这样一旦数据过多就会导致查询速度过慢倒向索引倒向索引弥补传统数据库正向索引中,查询词条过慢的技术根据ID,把正向索引数据以文档id和词条形式保存至倒向索引内,用户查询时根据词条使用B+树查询根据词条可以得到对应的ID,这样就可以根据ID直接查询数据库,避免数据库逐行查询Mysql和ESmysql和Es概念区别mysql和Es的关系mysql和Es是互补关系,一个项目中往往同时存在Mysql擅长事务操作,负责数据增删改 Es擅长海量数据搜索,负责查询安装安装Estex docker pull elasticsearch:7.17.7tex docker network create es-net```sh docker run -d \ --name elasticsearch \ -e ES_JAVA_OPTS="-Xms64m -Xmx128m" \ -e "discovery.type=single-node" \ -v es-data:/usr/share/elasticsearch/data \ -v es-plugins:/usr/share/elasticsearch/plugins \ --privileged \ --network es-net \ -p 9200:9200 \ -p 9300:9300 \ elasticsearch:7.17.7docker run -d \ --name elasticsearch \ -e "discovery.type=single-node" \ -v es-data:/usr/share/elasticsearch/data \ -v es-plugins:/usr/share/elasticsearch/plugins \ --privileged \ --network es-net \ -p 9200:9200 \ -p 9300:9300 \ elasticsearch:7.17.7 ```安装kibanakibana是一个Es可视化界面tex docker pull kibana:7.12.1```tex docker run -d \ --name kibana \ -e ELASTICSEARCH_HOSTS=http://elasticsearch:9200 \ --network es-net \ -p 5601:5601 \ kibana:7.12.1```安装分词器官方默认的分词方式对中文效果不好,因此需要额外下载一个分词器进入github下载对应的中文分词 https://github.com/medcl/elasticsearch-analysis-ik查找Es设置目录 tex docker volume inspect es-plugins将下载的压缩包解压,重命名为ik,并放入_data目录json POST /_analyze { "analyzer": "ik_smart", "text": "黄大旭真的帅" }分词器分词器拓展和停用ik分词器有ik_smart和ik_max_word通常情况下,分词器没法对当前热词进行分词,需要我们手动拓展,或者当我们需要手动设置敏感和无关词汇停用时,也需要手动配置在ik分词器目录中的config中的IKAnalyzer.cfg.xml定义自己的分词器DSL语句操作mapping属性mapping是对索引库中文档的约束,常见的索引有 type :字段数据类型,常见的简单类型有: 字符串:text(可分词的文本)、keyword(精准值,如:品牌、国家、Ip地址) 数值:long、interger、short、byte、double、float 布尔:boolean 日期:date 对象:object 坐标:geo_point(经纬度)、geo_shape(区域) 自动补全completion index:是否创建倒排索引,默认为ture(无倒排索引不会被查询) analyzer:使用哪种分词器 properties:该字段的子字段 创建索引库Es使用的是DQL语法,这个和json相似,也没必要记住,直接CVjson PUT /索引库名称 { "mappings": { "properties": { "字段名":{ "type": "text", "analyzer": "ik_smart" …

sentinel
type: item
date: 2025-07-18T21:37:08+08:00
description: 介绍在学习Sentinel前,我们需要了解Sentinel能解决什么问题面对的问题1.雪崩问题当一台服务宕机时,其关联的其他服务会一直等待响应从而宕机,因此照成雪崩 超时处理:设定请求超时时间,超过时间未响应则返回错误信息,不是无休止等待 舱壁模式:限定每个业务的线程数,避免因无休止等待照成资源堵塞而宕机 熔断降级:由断路器统计业务异常比例,达到阈值则拦截该业务一切请求 2.流量暴增服务请求QPS流量突然暴增,导致服务压力过大而宕机 流量控制,限制业务访问的QPS 同类保护技术对比Sentinel是由阿里巴巴开发的,一种相对成熟的服务器保护技术安装安装Sentinel管理页面在https://github.com/alibaba/Sentinel下载最新版Sentinel管理页面控制台输入shell java -jar sentinel-dashboard-1.8.6.jar -Dserver.port=对应端口进入页面:localhost:对应端口,默认账号密码为sentinel,若需要修改其他数据,课参考此表微服务整合Sentinel引入依赖```xml com.alibaba.cloud spring-cloud-starter-alibaba-sentinel ```配置application.properties```properties配置sentinelspring.cloud.sentinel.transport.dashboard=localhost:8090 ```访问业务的任意端口,触发sentinel监控指定监控资源sentinel默认只检测Controler,若需要指定检测资源,需要手动添加注解java @Service @SentinelResource("资源名") public void xxx(){ }properties spring.cloud.sentinel.web-context-unify = false整合Feginsentinel监控默认内部资源,若需要监控其连接状况,需要自定义 1. 修改配置properties fegin.sentinel.enable = ture 编写异常处理 java public class xxxClientFallbackFactory implements FallbackFatory<Fegin连接类>{ @Override public Fegin连接类 create(Throwable throwable){ return new Fegin连接类{ @Override public 返回类 Fegin方法 (){ //Fegin连接对应的方法,使用Sentinel隔离和熔断规则 return 返回需要的类型; } } } }3.Fegin连接类指定规则java @FeignClient(value="/xx",FallbackFatory=xxxClientFallbackFactory) public interface Fegin连接类{ @GetMapping("/xx") 返回类 Fegin方法(); }流控模式流控模式对服务的并发情况进行监控,分为QPS(流量监控)和线程监控(线程隔离) 直接:对当前资源限流,超过QPS/线程不予访问 关联:对当前资源限流,超过QPS/线程关联资源不予访问 链路:对当前资源(service/mapper)限流,超过QPS/线程不予对应链路的(controller)访问 QPS(流量监控)流量模式可针对服务接收的请求进行监控热点模式热点模式属于QPS(流量监控模式)的分支,可以对Restful(/{id})请求进行监控,可单独给该请求id设置独立的限流规则线程监控(线程隔离)当前技术下,线程隔离主要有一下两种 线程池隔离为服务开启指定线程,用于不用都一直占用内存优点:异步,不用等待线程开启缺点:服务器开销大 信号量隔离(sentinel使用)使用计数器计算服务线程数,线程数到阈值不开启线程优点:轻量缺点:不支持异常,需要等待线程开启 流控效果 快速失败:超过QPS/线程不予访问 warm up:服务刚开启时,阈值逐渐上升 排队等待:请求进入队列等待,计算每个请求的等待时间,超过阈值不予访问 熔断模式虽然限流可以防止高并发而导致服务崩坏,但服务还会因为其他原因而崩坏,为避免雪崩,需要设置熔断降级熔断降级会判断服务的异常比例(close模式),若高于阈值则关闭连接n秒(open模式),时间到尝试再一次放行请求查看是否异常(Half-open模式) 慢调用:熔断器计算请求连接时间,超出RT秒比例高于阈值则熔断 异常比例:熔断器计算请求抛出异常比例 异常数:熔断器计算请求抛出异常个数 授权模式只有携带…

任务调度
type: item
date: 2025-07-18T21:37:08+08:00
description: 任务调度技术任务调度是特定业务场景下的定时任务处理，在分布式架构下，分布式调度框架的设计显得尤为重要。这里简要介绍了两种常用的分布式调度框架Quartz和xxl-job的特性、基本架构和参数配置，以加深了解。Spring Schedulespring自带一种基于注解的任务调度在application中添加@EnableScheduling注解```java @SpringBootApplication @EnableScheduling //开启定时任务功能 public class SpringbootTaskApplication {public static void main(String[] args) { SpringApplication.run(SpringbootTaskApplication.class, args); } }```在定时任务类上添加规则和方法,使用cron表达式```java @Slf4j @Component public class MyJob {//@Scheduled(cron = "0/${mytask.abc:15} * * * * ?") 在application.yml配置中添加参数可以通过配置方式指定规则 mytask.abc = 10 ; @Scheduled(cron = "0,15,30,45 * * * * ?") public void hello(){ log.info("say hello"); } } ```Quartz介绍这是一个作业调度的开源项目,一般可用和spring结合使用,在实际开发中可用用 Quartz做一个定时任务,比如每小时执行一次,或每个月上午10点执行一次,每个月下午5点执行一次安装```xml org.springframework.boot spring-boot-starter-quartz ```使用 编写任务信息 编写任务处理规则 配置调度中心(启动时开启任务调度) 首先,先编写job类```java public class Job1 implements Job { private final SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");private void before() { System.out.println("任务1：开始执行-" + dateFormat.format(new Date())); } @Override public void execute(JobExecutionContext arg0) throws JobExecutionException { before(); System.out.println("任务1：业务逻辑。。。"); after(); } private void after() { System.out.println("任务1：执行结束"); System.out.println(); } ```再通过工具类配置规则```java @Component public class QuartzSchedulerManager { @Autowired private Scheduler scheduler;// 开始执行定时器 public void startJob() throws SchedulerException { startJob1(scheduler); startJob2(scheduler); scheduler.start(); } // 获取Job信息 public String getJobInfo(String name, String group) throws SchedulerException { TriggerKey triggerKey = new TriggerKey(name, group); CronTrigger cronTrigger = (CronTrigger) scheduler.getTrigger(triggerKey); return String.format("time:%s,state:%s", cronTrigger.getCronExpression(), scheduler.getTriggerState(triggerKey).name()); } // 修改某个任务的执行时间 public boolean modifyJob(String name, String group, String time) throws SchedulerException { Date date = n…

多级缓存
type: item
date: 2025-07-18T21:37:08+08:00
description: 多级缓存概述多级缓存是一种设计思路,充分利用请求的每个环境进行缓存,减少Tomcat的压力 一级缓存:浏览器客户端缓存,主要由cookie或LocalStroage 二级缓存:Nginx本地缓存 三级缓存:Redis缓存,主要由Nginx用Lua发起向Redis的询问 四级缓存:JVM缓存,进程缓存 五级缓存:本地数据库 JVM缓存JVM是一种基于本地进程的缓存,相较于Redis其使用本地缓存,没有网络开销(Redis可能使用其他服务器)速度更快,但是不能数据共享.常见的JVM缓存就是以静态变量的形式进行缓存,线程未结束,变量就不会被释放.Spring官方推荐使用Caffeine,其内部就是使用静态Map创建Caffeinejava //创建构造器 Cache<String,String> cache = Caffeine.newBuilder().build();创建构造器时可添加其他功能 initialCapacity(long):存储初始化大小 maximumSize(long):存储最大大小 expireAfterWrite(Duration.ofSeconds(long)):存储存long秒后释放 一般在Config里创建Caffeinejava @Configuration public class CaffeineConfig { @Bean public Cache<String,String> XXCache(){ Cache<String,String> cache = Caffeine.newBuilder() .initialCapacity(1) .maximumSize(1) .expireAfterWrite(Duration.ofSeconds(10)) .build(); return cache; } }使用Caffeinejava //存数据 cache.put("键","值");java //取数据,若无数据返回Null cache.getIfPresent("键"); //取数据,若无数据执行方法 cache.get("键",key->{ return ""; });Nginx使用RedisNginx配置修改使用前需要导入OpenResty```nginxuser nobody;worker_processes 1; error_log logs/error.log;events { worker_connections 1024; }http { include mime.types; default_type application/octet-stream; sendfile on; keepalive_timeout 65; #导入lua模块 lua_package_path "user/local/openrestry/lualib/?.lua;;"; #导入c模块 lua_package_cpath "user/local/openrestry/lualib/?.so;;"; #设置集群 upstream tomcat-cluster{ server tomcatIp1:端口; server tomcatIp2:端口; } server { #监听端口和域名 listen 8081; server_name localhost; #映射位置 location / { root html; index index.html index.htm; } location /item{ proxy_pass http://tomcat-cluster; } #设置某接口监听由lua脚本控制 location ~ /api/item/(\d+){ # 默认响应类型 default_type application/json; # 响应结果由lua/item.lua文件决定 content_by_lua_file lua/item.lua } error_page 500 502 503 504 /50x.html; location = /50x.html { root html; } } } ```导入common.lua```lua -- 导入redis local redis = require('resty.redis') -- 初始化redis local red = redis:new() red:set_timeouts(1000,1000,1000)-- 关闭redis连接的工具方法，其实是放入连接池 local function close_redis(red) local pool_max_idle_time = 10000 -- 连接的空闲时间，单位是毫秒 lo…

securityOuth2
type: item
date: 2025-07-18T21:37:08+08:00
description: 无论是密码登录还是第三方微信登录,我们都需要向前端返回一个token,这个过程就叫认证当用户向服务器发起请求时,会对token是否有效进行验证

seata
type: item
date: 2025-07-18T21:37:08+08:00
description: 微服务事务理论分布式系统无法完成三个指标,即CAP定理 Consistency(一致性):各服务之间数据一致 Availability(可用性):访问服务必须得到响应 Partition Tolerance(分区容错性):各服务之间异步执行,互不影响 事务问题在微服务中,一个服务出现问题,其关联的服务仍然会继续运行,这就容易出现事务问题出现这种原因是分布式不可避免的CAP定理,即分布式服务中(P),一旦A服务宕机,B服务为保持可用性(A),不会也跟着宕机,那么数据(C)就不一致,产生事务问题解决方法 AP模式:各服务在运行过程中,一旦出错则其关联服务执行弥补措施,即同时保证可用性(A)和分布式(P) 例:创建订单和扣减余额正常运行,但是扣减库存出现问题,那么就删除订单并添加余额 CP模式:各服务在运行过程中,等待其关联服务运行完成后再一起提交,即同时保证一致性(C)和分布式(P) 例:创建订单和扣减余额运行完成后等待扣减库存,扣减库存出现问题,则不提交事务无论是AP还是CP,都需要一个中间商检测各服务的健康状况,从而判断执行什么操作,因此我们需要一个事务协调者,即Seata认识Seata介绍Seata是一个微服务/分布式的事务管理框架,其主要有3各部分组成: TC-事务协调者:维护全局事务状态,协调全局事务提交或回滚 TM-事务管理器:定义全局事务范围、定义全局事务、提交或回滚全局事务 RM-资源管理器:管理分支事务资源,与TC交谈以注册事务和报告事务状态,并驱动分支事务提交或回滚 部署TC服务1.下载TC服务首先我们要下载seata-server包，地址在http://seata.io/zh-cn/blog/download.html2.修改本地配置```properties registry { # tc服务的注册中心类，这里选择nacos，也可以是eureka、zookeeper等 type = "nacos"nacos { # seata tc 服务注册到 nacos的服务名称，可以自定义 application = "seata-tc-server" serverAddr = "127.0.0.1:8848" group = "DEFAULT_GROUP" namespace = "" cluster = "SH" username = "nacos" password = "nacos" } }config { # 读取tc服务端的配置文件的方式，这里是从nacos配置中心读取，这样如果tc是集群，可以共享配置 type = "nacos" # 配置nacos地址等信息 nacos { serverAddr = "127.0.0.1:8848" namespace = "" group = "SEATA_GROUP" username = "nacos" password = "nacos" dataId = "seataServer.properties" } } ```3.nacos添加配置```properties数据存储方式，db代表数据库store.mode=db store.db.datasource=druid store.db.dbType=mysql store.db.driverClassName=com.mysql.jdbc.Driver store.db.url=jdbc:mysql://127.0.0.1:3306/seata?useUnicode=true&rewriteBatchedStatements=true store.db.user=root store.db.password=123 store.db.minConn=5 store.db.maxConn=30 store.db.globalTable=global_table store.db.branchTable=branch_table store.db.queryLimit=100 store.db.lockTable=lock_table store.db.maxWait=5000事务、日志等配置server.recovery.committingRetryPeriod=1000 server.recovery.asynCommittingRetryPeriod=1000 server.recovery.rollbackingRetryPeriod=1000 server.recovery.timeoutRetryPeriod=1000 server.maxCommitRetryTimeout=-1 server.maxRollbackRetryTimeout=-1 server.rollbackRetryTime…