多级缓存入门:Caffeine、Lua、OpenResty、Canal

之前写过——Google Guava Cache简介

本文系统学习一下多级缓存

目录

  • 0.什么是多级缓存
    • 商品查询业务案例导入
  • 1.JVM进程缓存
    • 初识Caffeine
    • 实现JVM进程缓存
  • 2.Lua语法入门
    • HelloWorld
    • 数据类型、变量和循环
    • 函数、条件控制
  • 3.Nginx业务编码实现多级缓存
    • 安装OpenResty
    • OpenResty快速入门
    • 请求参数处理
    • ☆实现OpenResty查询Tomcat
    • Redis缓存预热
    • ☆实现OpenResty查询Redis缓存
    • ☆实现Nginx本地(OpenResty)缓存
  • 4.☆缓存同步
    • 缓存同步策略
    • Canal初识与配置
    • 监听Canal实现缓存同步

0.什么是多级缓存

传统的缓存策略一般是请求到达Tomcat后,先查询Redis,如果未命中则查询数据库,如图:

在这里插入图片描述

存在下面的问题:

  • 请求要经过Tomcat处理,Tomcat的性能成为整个系统的瓶颈

  • Redis缓存失效时,会对数据库产生冲击

多级缓存就是充分利用请求处理的每个环节,分别添加缓存,减轻Tomcat压力,提升服务性能:

  • 浏览器访问静态资源时,优先读取浏览器本地缓存
  • 访问非静态资源(ajax查询数据)时,访问服务端
  • 请求到达Nginx后,优先读取Nginx本地缓存
  • 如果Nginx本地缓存未命中,则去直接查询Redis(不经过Tomcat)
  • 如果Redis查询未命中,则查询Tomcat
  • 请求进入Tomcat后,优先查询JVM进程缓存
  • 如果JVM进程缓存未命中,则查询数据库

在这里插入图片描述

在多级缓存架构中,Nginx内部需要编写本地缓存查询、Redis查询、Tomcat查询的业务逻辑,因此这样的nginx服务不再是一个反向代理服务器,而是一个编写业务的Web服务器了

因此这样的业务Nginx服务也需要搭建集群来提高并发,再有专门的nginx服务来做反向代理,如图:

在这里插入图片描述

另外,我们的Tomcat服务将来也会部署为集群模式:

在这里插入图片描述

可见,多级缓存的关键有两个

  • 一个是在nginx中编写业务,实现nginx本地缓存、Redis、Tomcat的查询

  • 另一个就是在Tomcat中实现JVM进程缓存

其中Nginx编程则会用到OpenResty框架结合Lua这样的语言。

这也是今天学习的难点和重点。

商品查询业务案例导入

为了演示多级缓存,我们先导入一个商品管理的案例,其中包含商品的CRUD功能。我们将来会给查询商品添加多级缓存。

1.安装MySQL

后期做数据同步需要用到MySQL的主从功能,所以需要大家在虚拟机中,利用Docker来运行一个MySQL容器。

1.1.准备目录

为了方便后期配置MySQL,我们先准备两个目录,用于挂载容器的数据和配置文件目录:

# 进入/tmp目录
cd /tmp
# 创建文件夹
mkdir mysql
# 进入mysql目录
cd mysql

1.2.运行命令

进入mysql目录后,执行下面的Docker命令:

docker run \-p 3306:3306 \--name mysql \-v $PWD/conf:/etc/mysql/conf.d \ # 挂载mysql配置文件目录-v $PWD/logs:/logs \ # 挂载mysql日志文件目录-v $PWD/data:/var/lib/mysql \ # 挂载mysql数据文件目录-e MYSQL_ROOT_PASSWORD=123 \ # 指定root账号和密码--privileged \-d \mysql:5.7.25

1.3.修改配置

在/tmp/mysql/conf目录添加一个my.cnf文件,作为mysql的配置文件:

# 创建文件
touch /tmp/mysql/conf/my.cnf

文件的内容如下,都是mysql的默认配置,主要配的就是字符的编码改成utf-8

[mysqld]
# 跳过域名解析,速度加载可以更快
skip-name-resolve
# 字符编码
character_set_server=utf8
# 指定数据库的目录 与我们挂载的目录保持一致
datadir=/var/lib/mysql
# 服务id
server-id=1000

1.4.重启

配置修改后,必须重启容器:

docker restart mysql


2.导入SQL

接下来,利用Navicat客户端连接MySQL,创建新的数据库,然后导入课前资料提供的sql文件:

/*Navicat Premium Data TransferSource Server         : 192.168.150.101Source Server Type    : MySQLSource Server Version : 50725Source Host           : 192.168.150.101:3306Source Schema         : heimaTarget Server Type    : MySQLTarget Server Version : 50725File Encoding         : 65001Date: 16/08/2021 14:45:07
*/SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;-- ----------------------------
-- Table structure for tb_item
-- ----------------------------
DROP TABLE IF EXISTS `tb_item`;
CREATE TABLE `tb_item`  (`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '商品id',`title` varchar(264) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '商品标题',`name` varchar(128) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '' COMMENT '商品名称',`price` bigint(20) NOT NULL COMMENT '价格(分)',`image` varchar(200) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '商品图片',`category` varchar(200) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '类目名称',`brand` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '品牌名称',`spec` varchar(200) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '规格',`status` int(1) NULL DEFAULT 1 COMMENT '商品状态 1-正常,2-下架,3-删除',`create_time` datetime NULL DEFAULT NULL COMMENT '创建时间',`update_time` datetime NULL DEFAULT NULL COMMENT '更新时间',PRIMARY KEY (`id`) USING BTREE,INDEX `status`(`status`) USING BTREE,INDEX `updated`(`update_time`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 50002 CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '商品表' ROW_FORMAT = COMPACT;-- ----------------------------
-- Records of tb_item
-- ----------------------------
INSERT INTO `tb_item` VALUES (10001, 'RIMOWA 21寸托运箱拉杆箱 SALSA AIR系列果绿色 820.70.36.4', 'SALSA AIR', 16900, 'https://m.360buyimg.com/mobilecms/s720x720_jfs/t6934/364/1195375010/84676/e9f2c55f/597ece38N0ddcbc77.jpg!q70.jpg.webp', '拉杆箱', 'RIMOWA', '{\"颜色\": \"红色\", \"尺码\": \"26寸\"}', 1, '2019-05-01 00:00:00', '2019-05-01 00:00:00');
INSERT INTO `tb_item` VALUES (10002, '安佳脱脂牛奶 新西兰进口轻欣脱脂250ml*24整箱装*2', '脱脂牛奶', 68600, 'https://m.360buyimg.com/mobilecms/s720x720_jfs/t25552/261/1180671662/383855/33da8faa/5b8cf792Neda8550c.jpg!q70.jpg.webp', '牛奶', '安佳', '{\"数量\": 24}', 1, '2019-05-01 00:00:00', '2019-05-01 00:00:00');
INSERT INTO `tb_item` VALUES (10003, '唐狮新品牛仔裤女学生韩版宽松裤子 A款/中牛仔蓝(无绒款) 26', '韩版牛仔裤', 84600, 'https://m.360buyimg.com/mobilecms/s720x720_jfs/t26989/116/124520860/644643/173643ea/5b860864N6bfd95db.jpg!q70.jpg.webp', '牛仔裤', '唐狮', '{\"颜色\": \"蓝色\", \"尺码\": \"26\"}', 1, '2019-05-01 00:00:00', '2019-05-01 00:00:00');
INSERT INTO `tb_item` VALUES (10004, '森马(senma)休闲鞋女2019春季新款韩版系带板鞋学生百搭平底女鞋 黄色 36', '休闲板鞋', 10400, 'https://m.360buyimg.com/mobilecms/s720x720_jfs/t1/29976/8/2947/65074/5c22dad6Ef54f0505/0b5fe8c5d9bf6c47.jpg!q70.jpg.webp', '休闲鞋', '森马', '{\"颜色\": \"白色\", \"尺码\": \"36\"}', 1, '2019-05-01 00:00:00', '2019-05-01 00:00:00');
INSERT INTO `tb_item` VALUES (10005, '花王(Merries)拉拉裤 M58片 中号尿不湿(6-11kg)(日本原装进口)', '拉拉裤', 38900, 'https://m.360buyimg.com/mobilecms/s720x720_jfs/t24370/119/1282321183/267273/b4be9a80/5b595759N7d92f931.jpg!q70.jpg.webp', '拉拉裤', '花王', '{\"型号\": \"XL\"}', 1, '2019-05-01 00:00:00', '2019-05-01 00:00:00');-- ----------------------------
-- Table structure for tb_item_stock
-- ----------------------------
DROP TABLE IF EXISTS `tb_item_stock`;
CREATE TABLE `tb_item_stock`  (`item_id` bigint(20) NOT NULL COMMENT '商品id,关联tb_item表',`stock` int(10) NOT NULL DEFAULT 9999 COMMENT '商品库存',`sold` int(10) NOT NULL DEFAULT 0 COMMENT '商品销量',PRIMARY KEY (`item_id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = COMPACT;-- ----------------------------
-- Records of tb_item_stock
-- ----------------------------
INSERT INTO `tb_item_stock` VALUES (10001, 99996, 3219);
INSERT INTO `tb_item_stock` VALUES (10002, 99999, 54981);
INSERT INTO `tb_item_stock` VALUES (10003, 99999, 189);
INSERT INTO `tb_item_stock` VALUES (10004, 99999, 974);
INSERT INTO `tb_item_stock` VALUES (10005, 99999, 18649);SET FOREIGN_KEY_CHECKS = 1;

其中包含两张表:

  • tb_item:商品表,包含商品的基本信息
  • tb_item_stock:商品库存表,包含商品的库存信息

之所以将库存分离出来,是因为库存是更新比较频繁的信息,写操作较多。而其他信息修改的频率非常低,如果放在一起,每次修改整条数据作废,那么缓存失效的频率就太高了,所以需要做数据分离,真实的商品数据可能要有好几张表,将来有好几个不同的缓存。



3.导入Demo工程

下面导入课前资料提供的工程,项目结构如图所示:

在这里插入图片描述

其中的业务包括:

  • 分页查询商品
  • 新增商品
  • 修改商品
  • 修改库存
  • 删除商品
  • 根据id查询商品
  • 根据id查询库存

业务全部使用mybatis-plus来实现

3.1.分页查询商品

com.heima.item.web包的ItemController中可以看到接口定义:

在这里插入图片描述

3.2.新增商品

com.heima.item.web包的ItemController中可以看到接口定义:

在这里插入图片描述

3.3.修改商品

com.heima.item.web包的ItemController中可以看到接口定义:

在这里插入图片描述

3.4.修改库存

com.heima.item.web包的ItemController中可以看到接口定义:

在这里插入图片描述

3.5.删除商品

com.heima.item.web包的ItemController中可以看到接口定义,这里是采用了逻辑删除,将商品状态修改为3。

在这里插入图片描述

3.6.根据id查询商品

com.heima.item.web包的ItemController中可以看到接口定义,这里只返回了商品信息,不包含库存

在这里插入图片描述

3.7.根据id查询库存

com.heima.item.web包的ItemController中可以看到接口定义

在这里插入图片描述

3.8.启动

注意修改application.yml文件中配置的mysql地址信息,需要修改为自己的虚拟机地址信息、还有账号和密码。

在这里插入图片描述

修改后,启动服务,访问:http://localhost:8081/item/10001即可查询商品数据,访问http://localhost:8081/item/stock/10001即可查询商品对应库存。



4.导入商品查询页面

商品查询是购物页面,与商品管理的页面是分离的。部署方式如图:

在这里插入图片描述

我们需要准备一个反向代理的nginx服务器,如上图红框所示,将静态的商品页面放到nginx目录中。

页面需要的数据通过ajax向服务端(nginx业务集群)查询。

4.1.运行nginx服务

这里我已经给大家准备好了nginx反向代理服务器和静态资源。

我们找到课前资料的nginx目录:

在这里插入图片描述

将其拷贝到一个非中文目录下,其中html目录存放着页面资源:

在这里插入图片描述

运行这个nginx服务。运行命令:

start nginx.exe

然后访问 http://localhost/item.html?id=10001即可访问商品:

在这里插入图片描述

4.2.反向代理

但是现在,页面是假数据展示的(前端写死)。我们需要向服务器发送ajax请求,查询商品数据。

打开控制台,可以看到页面有发起ajax查询数据:

在这里插入图片描述

而这个请求地址同样是80端口(没加端口默认html是80,也是Nginx 默认监听端口),所以被当前的nginx反向代理了,所以我们需要在当前的nginx做反向代理的配置。

查看nginx的conf目录下的nginx.conf文件:

在这里插入图片描述

其中的关键配置如下:

在这里插入图片描述

其中的192.168.150.101是我的虚拟机IP,也就是我的Nginx业务集群要部署的地方:

在这里插入图片描述

完整内容如下:


#user  nobody;
worker_processes  1;events {worker_connections  1024;
}http {include       mime.types;default_type  application/octet-stream;sendfile        on;#tcp_nopush     on;keepalive_timeout  65;# nginx的业务集群(在这里做nginx本地缓存、redis缓存、tomcat查询等)upstream nginx-cluster{# 还没做集群 先配一个 这里ip是我的虚拟机ipserver 192.168.150.101:8081;}server {listen       80;server_name  localhost;# /api接口反向代理到/nginx-cluster(nginx里的负载均衡的配置,在上面定义了)location /api {proxy_pass http://nginx-cluster;}location / {root   html;index  index.html index.htm;}error_page   500 502 503 504  /50x.html;location = /50x.html {root   html;}}
}

以上就是整个商品查询案例的导入了,我们把架子搭好了。tomcat有了,数据有了,反向代理服务器也准备好了,浏览器也有了,现在差的是下面框内的部分,下面我们去实现。

在这里插入图片描述



1.JVM进程缓存

初识Caffeine

缓存在日常开发中启动至关重要的作用,由于是存储在内存中,数据的读取速度是非常快的,能大量减少对数据库的访问,减少数据库的压力。我们把缓存分为两类:

  • 分布式缓存,例如Redis:
    • 优点:存储容量更大(Redis本身可以搭建集群)、可靠性更好(哨兵、主从)、可以在集群间共享(多台tomcat都可以访问同一个Redis缓存)
    • 缺点:访问缓存有网络开销(独立于tomcat之外)
    • 场景:缓存数据量较大、可靠性要求较高、需要在集群间共享
  • 进程本地缓存,例如HashMap、GuavaCache:
    • 优点:读取本地内存,没有网络开销,速度更快
    • 缺点:存储容量有限(上限就是这台tomcat服务器的JVM堆内存上限,而且不能独占,否则程序运行有问题)、可靠性较低(tomcat重启、宕机则数据丢失)、无法共享(tomcat与tomcat之间)
    • 场景:性能要求较高,缓存数据量较小

我们今天会利用Caffeine框架来实现JVM进程缓存。Caffeine是一个基于Java8开发的,提供了近乎最佳命中率的高性能的本地缓存库。目前Spring内部的缓存使用的就是Caffeine。GitHub地址

Caffeine的性能非常好,下图是官方给出的性能对比,可以看到Caffeine的性能遥遥领先

在这里插入图片描述

缓存使用的基本API:

@Test
void testBasicOps() {// 构建cache对象Cache<String, String> cache = Caffeine.newBuilder().build();// 存数据cache.put("gf", "迪丽热巴");// 取数据,不存在则返回nullString gf = cache.getIfPresent("gf");System.out.println("gf = " + gf);// 上面的取法不是用的最多的,因为一般缓存没命中要去查数据库,查完后再写到缓存里,把结果返回给用户// 去Caffeine也提供了这样的一个api取数据,包含两个参数:// 参数一:缓存的key// 参数二:Lambda表达式,表达式的参数就是缓存的key,方法体是自定义的后续逻辑(例如查询数据库),查询到的结果会被存入缓存,并且返回给调用者。// 优先根据key查询JVM缓存,如果未命中,则执行参数二的Lambda表达式,并将查询到的结果存入缓存中String defaultGF = cache.get("defaultGF", key -> {// 根据key去数据库查询数据return "柳岩";});System.out.println("defaultGF = " + defaultGF);
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/78739.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Python + Playwright:如何在Docker 容器运行测试?

Python + Playwright:如何在Docker 容器运行测试? 前言一、简介二、环境准备1. 安装 DockerWindows 用户macOS 用户Linux 用户(以 Ubuntu 为例)2. 启动 browserless 服务拉取 browserless 镜像启动 browserless 容器验证 browserless 是否启动成功三、创建自动化测试项目1.…

语音合成之四大语言模型(LLM)与TTS的深度融合

基于LLM的语音合成 1.技术架构1.1 LlaSA1.2 CosyVoice (和 CosyVoice2)1.3 SparkTTS 2 特性对比2.1 零样本语音克隆2.2 多语种支持2.3 可控语音生成2.4 计算效率和模型大小 总结 当前&#xff0c;在大型语言模型&#xff08;Large Language Models&#xff0c;LLMs&#xff09;…

使用 Conda 创建新环境

使用 Conda 创建新环境 在使用 Conda 进行包管理和环境隔离时&#xff0c;创建新环境是一个非常常见的操作。通过创建独立的环境&#xff0c;可以避免不同项目之间的依赖冲突&#xff0c;并且能够灵活地管理各个项目的运行环境。 以下是使用 Conda 创建和管理新环境的详细步骤…

Unity AssetBundle (AB) 打包详解

AssetBundle 是 Unity 提供的一种资源打包机制&#xff0c;允许开发者将游戏资源&#xff08;如模型、纹理、预制体等&#xff09;打包成独立的文件&#xff0c;便于动态加载和热更新。 一、AssetBundle 基础概念 1. 什么是 AssetBundle 资源压缩包&#xff0c;包含序列化资源…

Python flask入门

Python flask入门 一、路由1.1 常规路由1.2 动态路由1.3 路由的其他高级用法 二、变量规则2.1 示例1&#xff1a;字符串类型&#xff08;默认&#xff09;2.2 示例2&#xff1a;整数类型2.3 示例3&#xff1a;路径类型 三、自定义转换器3.1 核心组件详解3.2 工作流程详解 四、f…

AI赋能守护行车安全新防线,基于YOLOv5全系列【n/s/m/l/x】参数模型开发构建驾驶车辆场景下驾驶员疲劳分心驾驶行为智能检测预警系统

在当今社会&#xff0c;随着科技生产力的飞速发展&#xff0c;汽车早已成为人们日常出行不可或缺的交通工具。它不仅极大地提高了人们的出行效率&#xff0c;也为生活带来了诸多便利。然而&#xff0c;随着汽车保有量的不断增加&#xff0c;交通安全问题也日益凸显。疲劳驾驶和…

onloyoffice历史版本功能实现,版本恢复功能,编辑器功能实现 springboot+vue2

文章目录 onloyoffice历史版本功能实现&#xff0c;版本恢复功能&#xff0c;编辑器功能实现 springbootvue2前提 需要注意把这个 (改成自己服务器的ip或者域名) 改成 自己服务器的域名或者地址我使用的onloyoffice版本 8.1.3.41. onloyoffice服务器部署 搜索其他文章2. 前段代…

概率论与统计(不确定性分析)主要应用在什么方面?涉及到具体知识是什么?

用户问的是概率论与统计&#xff08;不确定性分析&#xff09;的主要应用方面&#xff0c;涉及的具体知识以及具体公式。首先&#xff0c;我需要确定概率论与统计在哪些领域有应用&#xff0c;比如工程、金融、医学、数据科学等等。然后&#xff0c;具体知识部分应该包括概率论…

如何利用快照与备份快速恢复服务器的数据

在服务器上利用**快照&#xff08;Snapshot&#xff09;**和**备份&#xff08;Backup&#xff09;**快速恢复数据&#xff0c;可显著减少停机时间并确保业务连续性。以下是具体操作步骤和最佳实践&#xff1a; --- ### **1. 快照&#xff08;Snapshot&#xff09;恢复** **适…

安卓APP开发项目源码

在移动互联网蓬勃发展的今天&#xff0c;安卓应用几乎覆盖了人们生活的方方面面。从社交、购物&#xff0c;到医疗、教育&#xff0c;APP 的需求呈指数级增长。然而&#xff0c;如何高效、低成本地开发一款质量可靠的安卓应用&#xff0c;仍是很多开发者和团队关注的核心问题。…

遨游三防|30200mAh、双露营灯三防平板,见证堆料天花板

在工业4.0与智能化转型的浪潮中&#xff0c;专业设备对性能、防护及场景适应性的要求日益严苛。遨游通讯作为国家级高新技术企业&#xff0c;依托“危、急、特”场景的深耕经验&#xff0c;推出的旗舰级产品AORO-P300三防平板&#xff0c;以30200mAh超大容量电池、双露营灯设计…

【Python】Matplotlib:立体永生花绘制

本文代码部分实现参考自CSDN博客&#xff1a;https://blog.csdn.net/ak_bingbing/article/details/135852038 一、引言 Matplotlib作为Python生态中最著名的可视化库&#xff0c;其三维绘图功能可以创造出令人惊叹的数学艺术。本文将通过一个独特的参数方程&#xff0c;结合极…

OpenCV 图形API(57)颜色空间转换-----将图像从 RGB 色彩空间转换为 YUV 色彩空间函数RGB2YUV()

操作系统&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 编程语言&#xff1a;C11 算法描述 将图像从 RGB 色彩空间转换为 YUV 色彩空间。 该函数将输入图像从 RGB 色彩空间转换为 YUV。R、G 和 B 通道值的常规范围是 0 到 255。 在进行线…

Kubernetes(K8S)入门阶段详细指南

Kubernetes(K8S)入门阶段详细指南 一、容器技术基础:Docker核心操作与理解 1.1 Docker核心操作 镜像管理: 拉取镜像:docker pull ubuntu(以Ubuntu为例)查看本地镜像:docker images删除镜像:docker rmi <image_id>容器生命周期管理: 启动容器:docker run -d -…

AI大模型学习十一:‌尝鲜ubuntu 25.04 桌面版私有化sealos cloud + devbox+minio,实战运行成功

一、说明 没意思&#xff0c;devbox私有化不支持&#xff0c;看来这个开源意义不大&#xff0c;和宣传差距很大啊&#xff0c;那devbox就不用玩 用了ubuntu 25.04&#xff0c;内核为GNU/Linux 6.14.0-15-generic x86_64&#xff0c;升级了部分image&#xff0c;过程曲折啊 se…

[GXYCTF2019]Ping Ping Ping

解题步骤 1、先使用 内敛执行 查看当前的php文件 执行 命令执行 发现空格被过滤 ?ip127.0.0.1$IFS|$IFSwhomi 还有一个点就是这个 执行的命令是不能进行拼接的 可能就是被过滤了 | 所以我们使用 ; 进行绕过一下 空格过滤代替 $IFS ${IFS} ${IFS}$9 //这里$1到$9都可以 $IFS$1…

重温TCP通信过程

文章目录 1. 慢启动2. 拥塞避免 3. 快速重传和快速恢复 初识tcp报文 我们先来简单认识一下报文的格式,具体理解需要后面详细介绍 源端口和目的端口:顾名思义就是标识传输双方的信息首部长度:指的是TCP报头的长度,换句话来说,我们需要用一个属性来描述报头的长度,就说明TCP的报…

力扣HOT100之链表:23. 合并 K 个升序链表

这道题我是用最淳朴最简单的思路去做的&#xff0c;用一个while循环持续地将当前遍历到的最小值加入到合并链表中&#xff0c;while循环中使用一个for循环遍历整个指针数组&#xff0c;将其中的最小值和对应下标记录下来&#xff0c;并将其值加入到合并链表中&#xff0c;同时对…

Spring Boot 支持政策

&#x1f9d1;&#x1f4bb; Spring Boot 支持政策 ✒️ Andy Wilkinson 于2023年12月7日编辑本页 32次修订 &#x1f4cc; 核心政策 &#x1f6e1;️ VMware Tanzu 开源支持政策 Spring Boot 针对关键错误和安全问题提供支持 &#x1f4c6; 版本支持周期 1️⃣ 主要版本&a…

WeakAuras Lua Script TOC BOSS2 <Lord Jaraxxus>

WeakAuras Lua脚本&#xff08;WA 字符串&#xff09; 十字军试炼老2 加拉克苏斯 血肉成灰 !WA:2!TIv7VnYrz8UXuDudiDN7PqFfCdTHKYLOeN7sBpXvKDIZf36Kyw7KRT3DYE2Dh7DAwV7CZSoXUOIewf4GdAfgbu13LPasv8MS4diavKoH4RSkIp0phXDT8je5FGYZmZU2oVCqrGLJZUpZZoZZB)EEz1wkr9ewjSU6MD5u…