当前位置: 首页 > news >正文

Spring Boot + MySQL 多线程查询与联表查询性能对比分析

Spring Boot + MySQL: 多线程查询与联表查询性能对比分析

背景

在现代 Web 应用开发中,数据库性能是影响系统响应时间和用户体验的关键因素之一。随着业务需求的不断增长,单表查询和联表查询的效率问题日益凸显。特别是在 Spring Boot 项目中,结合 MySQL 数据库进行复杂查询时,如何优化查询性能已成为开发者必须面对的重要问题。

在本实验中,我们使用了 Spring Boot 框架结合 MySQL 数据库,进行了两种常见查询方式的性能对比:多线程查询联表查询。通过对比这两种查询方式的响应时间,本文旨在探讨在实际业务场景中,选择哪种方式能带来更高的查询效率,尤其是在面对大数据量和复杂查询时的性能表现。


实验目的

本实验的主要目的是通过对比以下两种查询方式的性能,帮助开发者选择在不同业务场景下的查询方式:

  1. 联表查询(使用 SQL 语句中的 LEFT JOIN 等连接操作)
  2. 多线程查询(通过 Spring Boot 异步处理,分批查询不同表的数据)

实验环境

  • 开发框架:Spring Boot

  • 数据库:MySQL

  • 数据库表结构

    • test_a:主表,包含与其他表(test_btest_ctest_dtest_e)的关联字段。
    • test_btest_ctest_dtest_e:附表,分别包含不同的数据字段。

    这些表通过外键关联,test_a 表中的 test_b_idtest_c_idtest_d_idtest_e_id 字段指向各自的附表。

  • 数据量:约 100,000 条数据,分别在主表和附表中填充数据。

一.建表语句

主表A

CREATE TABLE `test_a` (`id` int NOT NULL AUTO_INCREMENT,`name` varchar(255) NOT NULL,`description` varchar(255) DEFAULT NULL,`test_b_id` int DEFAULT NULL,`test_c_id` int DEFAULT NULL,`test_d_id` int DEFAULT NULL,`test_e_id` int DEFAULT NULL,`created_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP,`updated_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;

附表b,c,d,e

CREATE TABLE `test_b` (`id` int NOT NULL AUTO_INCREMENT,`field_b1` varchar(255) DEFAULT NULL,`field_b2` int DEFAULT NULL,`created_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP,PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=792843462 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;CREATE TABLE `test_c` (`id` int NOT NULL AUTO_INCREMENT,`field_c1` varchar(255) DEFAULT NULL,`field_c2` datetime DEFAULT NULL,`created_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP,PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=100096 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;CREATE TABLE `test_d` (`id` int NOT NULL AUTO_INCREMENT,`field_d1` text,`field_d2` tinyint(1) DEFAULT NULL,`created_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP,PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=100300 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;CREATE TABLE `test_e` (`id` int NOT NULL AUTO_INCREMENT,`field_e1` int DEFAULT NULL,`field_e2` varchar(255) DEFAULT NULL,`created_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP,PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=100444 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;

二.填充数据

@SpringBootTest
class DemoTestQuerySpringbootApplicationTests {@Autowiredprivate TestAMapper testAMapper;@Autowiredprivate TestBMapper testBMapper;@Autowiredprivate TestCMapper testCMapper;@Autowiredprivate TestDMapper testDMapper;@Autowiredprivate TestEMapper testEMapper;@Testvoid contextLoads() {// 随机数生成器Random random = new Random();for (int i = 1; i <= 100000; i++) {// 插入 test_b 数据int testBId = insertTestB(random);// 插入 test_c 数据int testCId = insertTestC(random);// 插入 test_d 数据int testDId = insertTestD(random);// 插入 test_e 数据int testEId = insertTestE(random);// 插入 test_a 数据insertTestA(testBId, testCId, testDId, testEId, random);}}private int insertTestB(Random random) {TestB testB = new TestB();testB.setFieldB1("B Field " + random.nextInt(1000));testB.setFieldB2(random.nextInt(1000));testBMapper.insert(testB);  // 插入数据return testB.getId();  }private int insertTestC(Random random) {TestC testC = new TestC();testC.setFieldC1("C Field " + random.nextInt(1000));testC.setFieldC2(new java.sql.Timestamp(System.currentTimeMillis()));testCMapper.insert(testC);  // 插入数据return testC.getId();  }private int insertTestD(Random random) {TestD testD = new TestD();testD.setFieldD1("D Field " + random.nextInt(1000));testD.setFieldD2(random.nextBoolean());testDMapper.insert(testD);  // 插入数据return testD.getId();  }private int insertTestE(Random random) {TestE testE = new TestE();testE.setFieldE1(random.nextInt(1000));testE.setFieldE2("E Field " + random.nextInt(1000));testEMapper.insert(testE);  // 插入数据return testE.getId();  }private void insertTestA(int testBId, int testCId, int testDId, int testEId, Random random) {TestA testA = new TestA();testA.setName("Test A Name " + random.nextInt(1000));testA.setDescription("Test A Description " + random.nextInt(1000));testA.setTestBId(testBId);testA.setTestCId(testCId);testA.setTestDId(testDId);testA.setTestEId(testEId);testAMapper.insert(testA);  // 插入数据}}

三.配置线程池

3.1配置

/*** 实现AsyncConfigurer接口* 并重写了 getAsyncExecutor方法,* 这个方法返回 myExecutor(),* Spring 默认会将 myExecutor 作为 @Async 方法的线程池。*/
@Configuration
@EnableAsync
public class ThreadPoolConfig implements AsyncConfigurer {/*** 项目共用线程池*/public static final String TEST_QUERY = "testQuery";@Overridepublic Executor getAsyncExecutor() {return myExecutor();}@Bean(TEST_QUERY)@Primarypublic ThreadPoolTaskExecutor myExecutor() {//spring的线程池ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();//线程池优雅停机的关键executor.setWaitForTasksToCompleteOnShutdown(true);executor.setCorePoolSize(10);executor.setMaxPoolSize(10);executor.setQueueCapacity(200);executor.setThreadNamePrefix("my-executor-");//拒绝策略->满了调用线程执行,认为重要任务executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());//自己就是一个线程工程executor.setThreadFactory(new MyThreadFactory(executor));executor.initialize();return executor;}}

3.2异常处理

public class MyUncaughtExceptionHandler implements Thread.UncaughtExceptionHandler {private static final Logger log = LoggerFactory.getLogger(MyUncaughtExceptionHandler.class);@Overridepublic void uncaughtException(Thread t, Throwable e) {log.error("Exception in thread",e);}
}

3.3线程工厂

@AllArgsConstructor
public class MyThreadFactory implements ThreadFactory {private static final MyUncaughtExceptionHandler MyUncaughtExceptionHandler = new MyUncaughtExceptionHandler();private ThreadFactory original;@Overridepublic Thread newThread(Runnable r) {//执行Spring线程自己的创建逻辑Thread thread = original.newThread(r);//我们自己额外的逻辑thread.setUncaughtExceptionHandler(MyUncaughtExceptionHandler);return thread;}
}

四.Service查询方法

4.1left join连接查询

    @Overridepublic IPage<TestAll> getTestAllPage_1(int current, int size) {// 创建 Page 对象,current 为当前页,size 为每页大小Page<TestAll> page = new Page<>(current, size);return testAMapper.selectAllWithPage(page);}

对应的xml 的sql语句

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="org.fth.demotestqueryspringboot.com.test.mapper.TestAMapper"><!-- 基本的 ResultMap 映射 --><resultMap id="BaseResultMap" type="org.fth.demotestqueryspringboot.com.test.entity.vo.TestAll"><id column="test_a_id" jdbcType="INTEGER" property="testAId" /><result column="name" jdbcType="VARCHAR" property="name" /><result column="description" jdbcType="VARCHAR" property="description" /><result column="test_b_id" jdbcType="INTEGER" property="testBId" /><result column="test_c_id" jdbcType="INTEGER" property="testCId" /><result column="test_d_id" jdbcType="INTEGER" property="testDId" /><result column="test_e_id" jdbcType="INTEGER" property="testEId" /><result column="created_at" jdbcType="TIMESTAMP" property="createdAt" /><result column="updated_at" jdbcType="TIMESTAMP" property="updatedAt" /><!-- TestB --><result column="field_b1" jdbcType="VARCHAR" property="fieldB1" /><result column="field_b2" jdbcType="INTEGER" property="fieldB2" /><result column="test_b_created_at" jdbcType="TIMESTAMP" property="testBCreatedAt" /><!-- TestC --><result column="field_c1" jdbcType="VARCHAR" property="fieldC1" /><result column="field_c2" jdbcType="TIMESTAMP" property="fieldC2" /><result column="test_c_created_at" jdbcType="TIMESTAMP" property="testCCreatedAt" /><!-- TestD --><result column="field_d1" jdbcType="VARCHAR" property="fieldD1" /><result column="field_d2" jdbcType="BOOLEAN" property="fieldD2" /><result column="test_d_created_at" jdbcType="TIMESTAMP" property="testDCreatedAt" /><!-- TestE --><result column="field_e1" jdbcType="INTEGER" property="fieldE1" /><result column="field_e2" jdbcType="VARCHAR" property="fieldE2" /><result column="test_e_created_at" jdbcType="TIMESTAMP" property="testECreatedAt" /></resultMap><!-- 分页查询 TestA 和其他表的数据 --><select id="selectAllWithPage" resultMap="BaseResultMap">SELECTa.id AS test_a_id,a.name,a.description,a.test_b_id,a.test_c_id,a.test_d_id,a.test_e_id,a.created_at,a.updated_at,-- TestBb.field_b1,b.field_b2,b.created_at AS test_b_created_at,-- TestCc.field_c1,c.field_c2,c.created_at AS test_c_created_at,-- TestDd.field_d1,d.field_d2,d.created_at AS test_d_created_at,-- TestEe.field_e1,e.field_e2,e.created_at AS test_e_created_atFROM test_a aLEFT JOIN test_b b ON a.test_b_id = b.idLEFT JOIN test_c c ON a.test_c_id = c.idLEFT JOIN test_d d ON a.test_d_id = d.idLEFT JOIN test_e e ON a.test_e_id = e.id</select></mapper>

4.2多线程查询

 @Overridepublic IPage<TestAll> getTestAllPage_2(int current, int size) {IPage<TestA> testAPage = testAMapper.selectPage(new Page<>(current, size), null);List<TestA> testAS = testAPage.getRecords();CompletableFuture<List<TestB>> futureBs = selectTestBids(testAS.stream().map(TestA::getTestBId).collect(Collectors.toSet()));CompletableFuture<List<TestC>> futureCs = selectTestCids(testAS.stream().map(TestA::getTestCId).collect(Collectors.toSet()));CompletableFuture<List<TestD>> futureDs = selectTestDids(testAS.stream().map(TestA::getTestDId).collect(Collectors.toSet()));CompletableFuture<List<TestE>> futureEs = selectTestEids(testAS.stream().map(TestA::getTestEId).collect(Collectors.toSet()));// 等待所有异步任务完成并收集结果CompletableFuture<Void> allFutures = CompletableFuture.allOf(futureBs, futureCs, futureDs, futureEs);try {// 等待所有异步任务完成allFutures.get();} catch (InterruptedException | ExecutionException e) {e.printStackTrace();throw new RuntimeException("Failed to fetch data", e);}// 获取异步查询的结果List<TestB> bs = futureBs.join();List<TestC> cs = futureCs.join();List<TestD> ds = futureDs.join();List<TestE> es = futureEs.join();// 将结果映射到Map以便快速查找Map<Integer, TestB> bMap = bs.stream().collect(Collectors.toMap(TestB::getId, b -> b));Map<Integer, TestC> cMap = cs.stream().collect(Collectors.toMap(TestC::getId, c -> c));Map<Integer, TestD> dMap = ds.stream().collect(Collectors.toMap(TestD::getId, d -> d));Map<Integer, TestE> eMap = es.stream().collect(Collectors.toMap(TestE::getId, e -> e));List<TestAll> testAllList = testAS.stream().map(testA -> {TestAll testAll = new TestAll();testAll.setTestAId(testA.getId());testAll.setName(testA.getName());testAll.setDescription(testA.getDescription());testAll.setCreatedAt(testA.getCreatedAt());// 根据 testBId 填充 TestB 的字段if (testA.getTestBId() != null) {TestB testB = bMap.get(testA.getTestBId());if (testB != null) {testAll.setFieldB1(testB.getFieldB1());testAll.setFieldB2(testB.getFieldB2());testAll.setTestBCreatedAt(testB.getCreatedAt());}}// 根据 testCId 填充 TestC 的字段if (testA.getTestCId() != null) {TestC testC = cMap.get(testA.getTestCId());if (testC != null) {testAll.setFieldC1(testC.getFieldC1());testAll.setFieldC2(testC.getFieldC2());testAll.setTestCCreatedAt(testC.getCreatedAt());}}// 根据 testDId 填充 TestD 的字段if (testA.getTestDId() != null) {TestD testD = dMap.get(testA.getTestDId());if (testD != null) {testAll.setFieldD1(testD.getFieldD1());testAll.setFieldD2(testD.getFieldD2());testAll.setTestDCreatedAt(testD.getCreatedAt());}}// 根据 testEId 填充 TestE 的字段if (testA.getTestEId() != null) {TestE testE = eMap.get(testA.getTestEId());if (testE != null) {testAll.setFieldE1(testE.getFieldE1());testAll.setFieldE2(testE.getFieldE2());testAll.setTestECreatedAt(testE.getCreatedAt());}}return testAll;}).collect(Collectors.toList());// 创建并返回新的分页对象IPage<TestAll> page = new Page<>(testAPage.getCurrent(), testAPage.getSize(), testAPage.getTotal());page.setRecords(testAllList);return page;}@Asyncpublic CompletableFuture<List<TestB>> selectTestBids(Set<Integer> bids) {return CompletableFuture.supplyAsync(() -> testBMapper.selectBatchIds(bids));}@Asyncpublic CompletableFuture<List<TestC>> selectTestCids(Set<Integer> cids) {return CompletableFuture.supplyAsync(() -> testCMapper.selectBatchIds(cids));}@Asyncpublic CompletableFuture<List<TestD>> selectTestDids(Set<Integer> dids) {return CompletableFuture.supplyAsync(() -> testDMapper.selectBatchIds(dids));}@Asyncpublic CompletableFuture<List<TestE>> selectTestEids(Set<Integer> eids) {return CompletableFuture.supplyAsync(() -> testEMapper.selectBatchIds(eids));}

五.结果测试

5.1连接查询

在这里插入图片描述

在这里插入图片描述

查询结果表格

currentsize响应时间
12016ms
502023ms
1002022ms
5002052ms
200200213ms
500200517ms

5.2多线程查询

在这里插入图片描述

在这里插入图片描述

查询结果表格

currentsize响应时间
12018ms
502017ms
1002017ms
5002021ms
20020056ms
50020080ms

总结与建议

  • 选择联表查询:当数据量较小,或者查询逻辑较为简单时,使用联表查询可以更简单直接,查询性能也较为优秀。
  • 选择多线程查询:当面对大数据量或者复杂查询时,采用多线程查询将带来更显著的性能提升。通过异步并行查询,可以有效缩短响应时间,提升系统的整体性能。

在实际开发中,可以根据具体的业务需求和数据库的规模,合理选择查询方式,从而提高数据库查询效率,优化系统性能

相关文章:

Spring Boot + MySQL 多线程查询与联表查询性能对比分析

Spring Boot MySQL: 多线程查询与联表查询性能对比分析 背景 在现代 Web 应用开发中&#xff0c;数据库性能是影响系统响应时间和用户体验的关键因素之一。随着业务需求的不断增长&#xff0c;单表查询和联表查询的效率问题日益凸显。特别是在 Spring Boot 项目中&#xff0…...

C++小碗菜之二:软件单元测试

“没有测试的代码重构不能称之为重构&#xff0c;它仅仅是垃圾代码的到处移动” ——Corey Haines 目录 前言 什么是单元测试&#xff1f; 单元测试的组成 单元测试的命名 单元测试的独立性 Google Test 单元测试的环境配置与使用 1. Ubuntu下安装 Google Test 2. 编写…...

集成学习综合教程

一、前置知识 一个分类器的分类准确率在60%-80%&#xff0c;即&#xff1a;比随机预测略好&#xff0c;但准确率却不太高&#xff0c;我们可以称之为 “弱分类器”&#xff0c;比如CART&#xff08;classification and regression tree 分类与回归树&#xff09;。 反之&#x…...

Java NIO channel

channel(通道)&#xff0c;byteBuffer(缓冲区)&#xff0c;selector&#xff08;io多路复用&#xff09;&#xff0c;通道FileChannel,SocketChannel的transferTo,transferFrom,MappedByteBuffer实现了零拷贝。 JVM调操作系统方法&#xff0c;read,write&#xff0c;都可以送字…...

B3631 单向链表-模拟链表

来源 &#xff1a;题目链接-洛谷 B3631 单向链表 单向链表 题目描述 实现一个数据结构&#xff0c;维护一张表&#xff08;最初只有一个元素 1 1 1&#xff09;。需要支持下面的操作&#xff0c;其中 x x x 和 y y y 都是 1 1 1 到 1 0 6 10^6 106 范围内的正整数&…...

【C++】格式化输出详解:掌握 cout 的进阶用法

博客主页&#xff1a; [小ᶻ☡꙳ᵃⁱᵍᶜ꙳] 本文专栏: C 文章目录 &#x1f4af;前言&#x1f4af;格式化输出的理论概述&#x1f4af;控制输出宽度和填充字符setw 操作符setfill 操作符 &#x1f4af;控制浮点数的显示格式fixed 与 scientificsetprecision &#x1f4af;…...

【NoSQL数据库】Hbase基本操作——数据库表的增删改查

目录 一、Hbase原理 二、HBase数据库操作 三、遇到的问题和解决方法 一、Hbase原理 HBase的数据模型&#xff1a; 行键 时间戳 列族&#xff1a;contents 列族&#xff1a;anchor 列族&#xff1a;mime “com.cnn.www” T9 Achor:cnnsi.com”CNN” T8 Achor:…...

同步fifo

同步FIFO FIFO即是一种先进先出的数据缓存器。同步FIFO指的是数据的写入和读出的时钟是同一个时钟。异步 FIFO 有两个时钟信号&#xff0c;读和写逻辑用的各自的读写时钟。 FIFO没有外部读写地址线&#xff0c;使用起来简单。但是缺点就是只能先入先出&#xff0c;数据地址由…...

肌肉骨骼肿瘤治疗市场:潜力无限,未来可期

肌肉骨骼肿瘤治疗作为现代医学的重要分支&#xff0c;专注于应对骨骼和肌肉系统中的良性和恶性肿瘤。随着全球人口老龄化和生活方式的改变&#xff0c;肌肉骨骼疾病日益成为公共卫生的重要问题。与此同时&#xff0c;医疗技术的进步和患者对高质量医疗服务的需求不断推动该市场…...

高考倒计时:用倒计时软件 为梦想加油 可用于教室黑板或者电脑上

高考&#xff0c;这个被无数学子视为人生重要转折点的考试&#xff0c;即将来临。每一年的六月&#xff0c;都充满了紧张与期待。如何在这场人生的战役中取得胜利&#xff1f;除了日常的勤奋学习&#xff0c;科学的复习计划和心态调整外&#xff0c;一款好用的倒计时软件&#…...

人工智能学习用的电脑安装cuda、torch、conda等软件,版本的选择以及多版本切换

接触人工智能的学习三个月了&#xff0c;每天与各种安装包作斗争&#xff0c;缺少依赖包、版本高了、版本低了、不兼容了、系统做一半从头再来了。。。这些都是常态。三个月把单位几台电脑折腾了不下几十次安装&#xff0c;是时候总结一下踩过的坑和积累的经验了。 以一个典型的…...

BERT模型的输出格式探究以及提取出BERT 模型的CLS表示,last_hidden_state[:, 0, :]用于提取每个句子的CLS向量表示

说在前面 最近使用自己的数据集对bert-base-uncased进行了二次预训练&#xff0c;只使用了MLM任务&#xff0c;发现在加载训练好的模型进行输出CLS表示用于下游任务时&#xff0c;同一个句子的输出CLS表示都不一样&#xff0c;并且控制台输出以下警告信息。说是没有这些权重。…...

InfluxDB 集成 Grafana

将InfluxDB集成到Grafana进行详细配置通常包括以下几个步骤&#xff1a;安装与配置InfluxDB、安装与配置Grafana、在Grafana中添加InfluxDB数据源以及创建和配置仪表板。以下是一个详细的配置指南&#xff1a; 一、安装与配置InfluxDB 下载与安装&#xff1a; 从InfluxDB的官…...

Vue跨标签通讯(本地存储)(踩坑)

我司有一个需求【用户指引】 需求是根标签有一个用户指引总开关&#xff0c;可以控制页面所有的用户指引是否在页面进入后初始是否默认打开&#xff0c;但是有些页面会新开标签这就设计到跨标签通讯了 我采取的方案是本地存储 重点:首先本地存储在页面是同源(即域名协议端口三…...

掌握创意之钥:全面解析HTML5 Canvas

在数字时代&#xff0c;表达创意的方式多种多样&#xff0c;而 HTML5 中的 <canvas> 元素无疑为网页开发者提供了一个强大的工具箱。无论你是想要创建动态图表、互动游戏还是复杂的可视化应用&#xff0c;掌握 Canvas 的基本用法都是迈向成功的关键一步。本文将带你一步步…...

mac port 安装redis 并设置为系统服务 自定义配置方法

mac系统中&#xff0c;port 包管理工具比brew的速度快N倍&#xff0c;今天就给大家分享一下在macos系统中如何使用 port安装 redis数据库并配置为服务自动启动和自定义redis.conf配置的方法。 1. 安装redis sudo port install redis 2. 启动redis服务 sudo port load redis …...

Agent AI: Surveying the Horizons of Multimodal Interaction---摘要、引言、代理 AI 集成

题目 智能体AI:多模态交互视野的考察 论文地址&#xff1a;https://arxiv.org/abs/2401.03568 图1&#xff1a;可以在不同领域和应用程序中感知和行动的Agent AI系统概述。Agent AI是正在成为通用人工智能&#xff08;AGI&#xff09;的一个有前途的途径。Agent AI培训已经证…...

二百七十八、ClickHouse——将本月第一天所在的那一周视为第一周,无论它是从周几开始的,查询某个日期是本月第几周

一、目的 ClickHouse指标表中有个字段week_of_month&#xff0c;含义是这条数据属于本月第几周。 而且将本月第一天所在的那一周视为第一周&#xff0c;无论它是从周几开始的。比如2024-12-01是周日&#xff0c;即12月第一周。而2024-12-02是周一&#xff0c;即12月第二周 二…...

Unity 相机旋转及角度限制

前言 由于欧拉角具有直观的可读性&#xff0c;做相机旋转时选择修改eulerAngles 来实现旋转&#xff0c;但实际效果与预期稍有不同&#xff0c;这是因为欧拉角受到万向锁&#xff08;Gimbal Lock&#xff09;的影响&#xff0c;在赋值时需要对输入的角度进行调整。 if (value…...

基于CentOS系统利用Kamailio搭建企业级SIP服务器

一、Kamailio简介 Kamailio是一款开源的SIP服务器&#xff0c;具有高性能、可扩展、模块化等特点。它广泛应用于VoIP、即时通讯、视频会议等领域。Kamailio支持多种操作系统&#xff0c;如Linux、FreeBSD等&#xff0c;可以与其他开源项目&#xff08;如 Asterisk、FreeSWITCH…...

部署项目报错

vue2项目部署后 Error: Cannot find module /views/*** 1.起因 登录页、首页等静态页面可以正常进入&#xff0c;后端访问也正常&#xff0c;可以获取到验证码。 但是登录之后会发现首页空白或者进入不到首页 F12查看有报错信息&#xff1a;Error: Cannot find module ‘/v…...

【AIGC】大模型面试高频考点-位置编码篇

【AIGC】大模型面试高频考点-位置编码篇 &#xff08;一&#xff09;手撕 绝对位置编码 算法&#xff08;二&#xff09;手撕 可学习位置编码 算法&#xff08;三&#xff09;手撕 相对位置编码 算法&#xff08;四&#xff09;手撕 Rope 算法&#xff08;旋转位置编码&#xf…...

钓鱼攻击详解:鱼叉攻击与水坑攻击

钓鱼攻击详解&#xff1a;鱼叉攻击与水坑攻击 在现代网络安全领域中&#xff0c;钓鱼攻击&#xff08;Phishing&#xff09;是一种最常见且有效的攻击手段。它通过欺骗用户&#xff0c;引导其泄露敏感信息或执行恶意操作&#xff0c;从而为攻击者打开大门。本文将深入介绍两种…...

如何在自动化安全测试中,实现多工具集成与数据融合,以提高对Spring Boot应用程序安全漏洞的检测效率与准确性?

为了在自动化安全测试中实现多工具集成与数据融合&#xff0c;以提高对Spring Boot应用程序安全漏洞的检测效率与准确性&#xff0c;可以采取以下策略和方法&#xff1a; 文章目录 1. 工具选择与集成2. 数据标准化与聚合3. 数据分析与融合4. 持续改进5. 实施示例 1. 工具选择与…...

框架篇面试

一、Spring框架中的单例bean的安全性 Spring框架中有一个Scope注解&#xff0c;默认的值就是singleton&#xff0c;单例的&#xff1b;因为一般在spring的bean中注入的都是无状态的对象&#xff0c;所以没有线程安全问题。但是如果在bean中定义了可修改的成员变量&#xff0c;…...

STM32滴答定时器SysTick理解+时基设置(4.1)

文章目录 1. 什么是滴答定时器&#xff1f;2. SysTick定时器初始化2.1 systick定时器时钟源&#xff1f;2.2 定时器四个寄存器 3 函数设置3.1SysTick_Config&#xff08;uint32_t ticks&#xff09;函数3.2初始化函数 4. 延时函数实现4.1 ms延时思路及实现4.2 us延时 1. 什么是…...

数字化时代下的企业合规管理:全球化背景下的挑战与机遇

在全球化浪潮的推动下&#xff0c;企业合规管理已成为企业发展中不可或缺的一部分。随着各国法规日益严格&#xff0c;以及数字化技术的飞速发展&#xff0c;企业在扩展业务的同时&#xff0c;也面临着越来越多的合规挑战。有效的合规管理不仅有助于提高企业的管理水平和运营效…...

读《Effective Java》笔记 - 条目17

条目17&#xff1a;使可变性最小化 为什么要使可变性最小化&#xff1f; 不可变对象天然是线程安全的&#xff0c;可以在多个线程之间安全共享。而可变对象需要添加额外的同步机制保证线程安全。不可变对象一旦创建就不会改变&#xff0c;便于追踪和理解代码。而可变对象的状态…...

对比json数据是否变化

在 JavaScript 中&#xff0c;你可以使用多种方法来对比两个 JSON 数据是否发生变化。以下是几种常见的方式&#xff1a; 1. 使用 JSON.stringify 最简单的方法是将两个 JSON 对象序列化为字符串&#xff0c;并比较这些字符串。但需要注意的是&#xff0c;这种方法对于对象属…...

云计算实验室建设方案

一、云计算实验室建设方案 云计算实验教学整体解决方案&#xff0c;包括&#xff1a;云计算服务器集群、云计算实训平台、实训课程体系、行业实战课程系统、行业数据等&#xff0c;系统性地解决云计算实训教学的痛点问题。 【硬件系统】云计算实训一体机 云计算实训一体机是唯…...

一、理论基础-PSI

之前参加了隐语第2期&#xff0c;对隐语SecretFlow框架有了大致的了解&#xff0c;这次参加隐语第4期&#xff0c;学习下PSI和PIR。 一、PSI定义 首先介绍PSI的定义&#xff0c;PSI&#xff08;隐私集合求交&#xff0c;Private Set Intersection即PSI)是安全多方计算&#x…...

C++学习0.2: RAII

引用&#xff1a; 【代码质量】RAII在C编程中的必要性_raii 在c中的重要性-CSDN博客 C RAII典型应用之lock_guard和unique_lock模板_raii lock-CSDN博客 前言: 常用的线程间同步/通信&#xff08;IPC&#xff09;方式有锁&#xff08;互斥锁、读写锁、自旋锁&#xff09;、…...

机器学习基础

了解机器学习的基本概念&#xff0c;如监督学习、无监督学习、强化学习、模型评估指标&#xff08;准确率、召回率、F1分数等&#xff09;。 机器学习&#xff08;Machine Learning&#xff0c;ML&#xff09;是人工智能&#xff08;AI&#xff09;的一个分支&#xff0c;它使计…...

传输层TCP_三次握手四次挥手的过程

三次握手四次挥手 三次握手 三次握手...

AI主流的生成式工作流框架

根据搜索结果&#xff0c;以下是一些2024年比较主流的生成式工作流框架&#xff1a; 1. LangChain&#xff1a;LangChain是一个用于构建生成式AI工作流的开发框架&#xff0c;它支持多种语言模型、工具、数据源及其他系统的集成。 2. DSPy&#xff1a;DSPy是一个生成式AI工作…...

【WRF后处理】WRF时区(UTC)需转化为北京时间(CST)!!!

目录 WRF运行时间标准注意事项-本地时区问题 输入数据&#xff1a;ERA5时间标准ERA5数据和WRF模型需要转换为北京时间&#xff01;&#xff01;&#xff01;北京时间&#xff08;CST&#xff09;与协调世界时&#xff08;UTC&#xff09;的关系转换方法 参考 WRF运行时间标准 …...

Qt 2D绘图之五:图形视图框架的结构、坐标系统和框架间的事件处理与传播

参考文章链接: Qt 2D绘图之五:图形视图框架的结构和坐标系统 Qt 2D绘图之六:图形视图框架的事件处理与传播 图形视图框架的结构 在前面讲的基本绘图中,我们可以自己绘制各种图形,并且控制它们。但是,如果需要同时绘制很多个相同或不同的图形,并且要控制它们的移动、…...

游戏引擎学习第34天

仓库:https://gitee.com/mrxiao_com/2d_game #这天内容比较多 开场介绍 游戏开发行业的基础是使用C和C编程&#xff0c;这是当今几乎所有游戏的开发标准。市面上广受欢迎的游戏&#xff0c;如《使命召唤》或《侠盗猎车手》&#xff0c;它们的底层代码和引擎几乎无一例外地采…...

深度学习笔记——模型压缩和优化技术(蒸馏、剪枝、量化)

本文详细介绍模型训练完成后的压缩和优化技术&#xff1a;蒸馏、剪枝、量化。 文章目录 1. 知识蒸馏 (Knowledge Distillation)基本概念工作流程关键技术类型应用场景优势与挑战优势挑战 总结 2. 权重剪枝 (Model Pruning)基本原理二分类1. 非结构化剪枝&#xff08;Unstructur…...

[在线实验]-RabbitMQ镜像的下载与部署

镜像下载 docker的rabbitmq镜像资源-CSDN文库 加载镜像 docker load --input rabbitmq.tar 给镜像打标签 这里发现镜像名为none&#xff0c;需要给镜像重命名下 docker tag [镜像id] [新镜像名称]:[新镜像标签] docker tag ebaf409ffbe2 rabbitmq:management 运行镜像…...

Netty 入门应用:结合 Redis 实现服务器通信

在上篇博客中&#xff0c;我们了解了 Netty 的基本概念和架构。本篇文章将带你深入实践&#xff0c;构建一个简单的 Netty 服务端&#xff0c;并结合 Redis 实现一个数据存取的示例。在这个场景中&#xff0c;Redis 作为缓存存储&#xff0c;Netty 作为服务端处理客户端请求。通…...

推荐 编译器c++

网页型 https://www.acgo.cn/playground C 在线工具 | 菜鸟工具 AcWing - 在线题库 ZJYYC在线测评系统 少儿编程竞赛在线学习 登录 - JOYSKID 余博士教编程_酷哥OJ_酷哥爱编程_酷哥创客AI编程 登录 - Luogu Spilopelia 软件型 DEV-c Dev C软件下载...

【新品发布】ESP32-P4开发板 —— 启明智显匠心之作,为物联网及HMI产品注入强劲动力

核心亮点&#xff1a; ESP32-P4开发板&#xff0c;是启明智显精心打造的一款高性能物联网开发板。它专为物联网项目及HMI&#xff08;人机界面&#xff09;产品而设计&#xff0c;旨在为您提供卓越的性能和稳定可靠的运行体验。 强大硬件配置&#xff1a; 双核400MHz RISC-V处…...

MeterSphere 使用脚本处理数据

1、前置/后置脚本 支持BeanShell(JSR223)、python、groovy、JavaScript脚本语言&#xff0c;推荐BeanShell(JSR223)。 在前置脚本中可以直接引用JMeter 预定义对象&#xff0c;例如&#xff1a; -- log&#xff1a;用于在脚本执行过程中打印日志 //打印“Hello World!”到info…...

如何获取谷歌新闻API密钥?

在信息获取和新闻传播领域&#xff0c;快速获取最新的新闻动态至关重要。谷歌新闻API为开发者提供了强大的工具&#xff0c;能够方便地集成全球各类新闻内容。通过使用该API&#xff0c;开发者可以实现对新闻的实时访问和管理&#xff0c;为用户提供丰富的信息服务。本文将指导…...

【全网最新】若依管理系统基于SpringBoot的前后端分离版本开发环境配置

目录 提前准备&#xff1a; 下载源代码 设置依赖 设置后台连接信息 运行后台 运行前端 安装npm依赖 启动前端 登录网页客户端 提前准备&#xff1a; 1、安装mysql 5以上就可以。 2、安装redis. 3、安装npm npm下载地址&#xff1a;https://nodejs.org/dist/v22.12…...

备赛蓝桥杯--算法题目(3)

1. 2的幂 231. 2 的幂 - 力扣&#xff08;LeetCode&#xff09; class Solution { public:bool isPowerOfTwo(int n) {return n>0&&n(n&(-n));} }; 2. 3的幂 326. 3 的幂 - 力扣&#xff08;LeetCode&#xff09; class Solution { public:bool isPowerOfT…...

如何解决 java.nio.charset.CoderMalfunctionError: 编码器故障错误问题?亲测有效的解决方法!

java.nio.charset.CoderMalfunctionError 是一个在 Java 中相对较少遇到的异常&#xff0c;通常与字符编码转换过程中的错误有关。当 Java 程序在进行字符编码转换时&#xff0c;遇到无法处理的字符或编码故障时&#xff0c;就会抛出该异常。 1. 问题描述 java.nio.charset.C…...

电气自动化 基于PLC控制的四路抢答器设计

摘要 本文描述了一款用三菱FX3U-48M可编程控制器设计的四路抢答器的系统构成、设计思路和功能。此抢答系统除了有基本抢答功能之外&#xff0c;还有计时、计算得分、亮灯提提示以及蜂鸣提醒功能。程序中设定答题时间&#xff0c;在主持人未按下开始抢答按钮之前&#xff0c;选…...

GA优化后的RBF神经网络

遗传算法&#xff08;Genetic Algorithm, GA&#xff09;优化后的RBF&#xff08;Radial Basis Function&#xff09;神经网络是一种结合进化算法与神经网络的混合模型&#xff0c;用于改进RBF神经网络的性能。以下是该模型的基本原理和相关公式&#xff1a; clear all close a…...