深入MySQL、JVM与Maven核心原理
一、MySQL多实例部署实战:二进制与软件源双方案解析
二进制部署
更新软件源
更新并重载
安装
注意:ubuntu24系统没有libaio1的包,需要单独去下载安装
创建用户组和用户
获取软件,安装解压
定制一个边界脚本
创建主配置文件
创建依赖目录
更改文件属性
启动
查看状态
端口上线
测试连接,成功!
接下来进行一些简单的操作
查看当前有哪些数据库
创建数据库
使用某个数据库,并查看使用的哪个数据库
创建一个表,需要提前进行属性编写
查看表属性
字段说明:
id
:主键,自动增长
name
:用户名,不能为空
email
:邮箱,唯一约束
age
:年龄
created_at
:创建时间,自动设置为当前时间
查看本数据库下有多少表
增加一条内容,增加多条内容时,只需要写多个括号即可
查看表内信息
更改数据
删除数据
软件源部署(YUM/DNF)
启动软件,并检查运行状态
登录设置新密码
二、JVM内存模型深度剖析:内存分区、OOM场景与GC机制
JVM 内存分区结构
1. 程序计数器
作用:当前线程所执行的字节码的行号指示器。字节码解释器通过改变这个计数器的值来选取下一条需要执行的字节码指令。它是程序控制流的指示器。
存储内容:正在执行的虚拟机字节码指令的地址。
OOM场景:此区域是唯一一个在《Java虚拟机规范》中没有规定任何 OutOfMemoryError
情况的区域。因为它的生命周期与线程相同,线程结束后计数器内存自然释放。
2. Java 虚拟机栈
作用:描述Java方法执行的线程内存模型。每个方法被执行时,JVM都会同步创建一个栈帧,用于存储局部变量表、操作数栈、动态链接、方法出口等信息。方法的调用到执行完成,对应着一个栈帧在虚拟机栈中从入栈到出栈的过程。
存储内容:栈帧。
OOM场景:
如果线程请求的栈深度大于虚拟机所允许的深度(例如无限递归)。
如果JVM栈容量可以动态扩展,而在扩展时无法申请到足够的内存。
3. 本地方法栈
作用:与虚拟机栈非常相似,其区别只是为虚拟机使用到的本地(Native)方法服务。
存储内容:Native方法执行的相关信息。
OOM场景:与Java虚拟机栈相同。
4. Java 堆
作用:是JVM管理的内存中最大的一块。此内存区域的唯一目的就是存放对象实例。几乎所有的对象实例以及数组都在这里分配内存。“
存储内容:对象实例、数组。
OOM场景:最常见的OOM发生地。当堆中没有内存完成实例分配,并且堆无法再扩展时,抛出 OutOfMemoryError
。
5. 方法区
作用:用于存储已被虚拟机加载的类型信息、常量、静态变量、即时编译器编译后的代码缓存等数据。
存储内容:类信息(版本、字段、方法、接口)、运行时常量池、静态变量。
OOM场景:如果方法区无法满足新的内存分配需求,则会抛出 OutOfMemoryError
。例如,借助CGLib等动态生成大量类。
Minor GC、Major GC 与 Full GC 的区别与触发条件
1. Minor GC / Young GC
目标区域:新生代。新生代又分为Eden区和两个Survivor区(S0, S1)。
触发条件:当Eden区空间不足时触发。
过程:将Eden区和其中一块Survivor区中仍然存活的对象,复制到另一块Survivor区。然后清空Eden和S0。对象每在Young GC中存活一次,年龄就加1,达到一定阈值后,会被晋升到老年代。
特点:发生频繁,回收速度快。因为新生代中大部分对象都是“朝生夕死”的,采用复制算法效率很高。
2. Major GC / Old GC
目标区域:老年代。
触发条件:情况较为复杂,通常由老年代空间不足引起。具体触发条件取决于使用的垃圾收集器。
例如,在CMS收集器中,有一个后台线程定期扫描老年代空间使用率,当超过一定阈值时触发。
特点:通常伴随着至少一次Minor GC。速度一般比Minor GC慢10倍以上。
3. Full GC
目标区域:整个堆内存(新生代 + 老年代)以及方法区(元空间)。
触发条件(常见):
老年代空间不足:当准备触发Major GC时,如果发现老年代剩余空间不足以存放从新生代晋升上来的对象,则会先触发Minor GC,如果之后老年代空间仍然不足,则触发Full GC。
方法区(元空间)空间不足。
空间分配担保失败:在发生Minor GC后,老年代的剩余空间不足以容纳新生代所有存活对象。
特点:Stop-The-World时间最长,对应用性能影响最大,应尽量避免其频繁发生。
三、JVM垃圾收集器对比:3种经典与现代收集器原理与选型指南
概述
垃圾收集器是JVM内存管理的关键组件,主要目标是高效地回收不再使用的对象,释放内存。没有“最好”的收集器,只有“最合适”的收集器。选择取决于应用的核心诉求:高吞吐量 还是 低延迟。
1. Parallel Scavenge / Parallel Old (PS + PO)
这是一对在JDK 8及之前版本中默认的垃圾收集器组合,是吞吐量优先的经典代表。
工作原理:
新生代 :使用复制算法。它会开启多个GC线程进行垃圾回收,在垃圾回收时,会暂停所有用户线程。
老年代 :使用标记-整理算法。是Parallel Scavenge的老年代版本,同样采用多线程并行回收。
优点:高吞吐量:核心目标。在多核CPU环境下,利用并行回收,能最大限度地减少GC本身消耗的时间,让CPU更多地用于业务计算。
缺点:高延迟:在进行GC时,STW时间较长,会导致应用停顿明显,不适合对响应时间敏感的应用。
适用场景:
后台计算、科学计算、数据批处理等。
不涉及太多用户交互,对响应时间要求不高的应用。
2. CMS (Concurrent Mark Sweep)
CMS是一款以获取最短回收停顿时间为目标的收集器,是低延迟的经典代表。
工作原理:采用 “标记-清除”算法,其过程相对复杂,分为4步:
1初始标记:STW。仅标记GC Roots能直接关联到的对象,速度很快。
2并发标记:无STW。从初始标记的对象开始,进行可达性分析,标记存活对象。这个阶段与用户线程并发执行。
3重新标记:STW。修正并发标记期间,因用户线程继续运行而导致标记产生变动的那部分对象。停顿时间比初始标记稍长,但远短于并发标记。
4并发清除:无STW。清理死亡对象,与用户线程并发执行。
优点:低延迟:由于最耗时的“并发标记”和“并发清除”阶段都不需要暂停应用,整个回收过程的停顿时间非常短。
缺点:
对CPU资源敏感:并发阶段会占用一部分线程(CPU资源),导致应用程序吞吐量降低。
无法处理“浮动垃圾”:并发清理阶段用户线程还在运行,可能会产生新的垃圾,只能留到下一次GC处理。
内存碎片:使用“标记-清除”算法会产生内存碎片。可能触发Full GC进行碎片整理。
适用场景:
Web服务器、B/S系统服务端等对延迟敏感的应用。
3. G1 (Garbage-First)
G1是面向服务端应用的垃圾收集器,旨在替代CMS。它是一款 “吞吐量”与“低延迟”兼顾的现代收集器,也是JDK 9及之后的默认收集器。
工作原理:
区域化:G1将整个Java堆划分为多个大小相等的独立区域(Region)。新生代和老年代不再是物理隔离,而是一系列Region的集合。
可预测的停顿时间模型:G1跟踪各个Region里面的垃圾堆积“价值”大小(回收所能释放的空间大小及回收所需时间的经验值),在后台维护一个优先列表。
回收过程:主要包括:
新生代GC:与Parallel Scavenge类似,STW,多线程复制存活对象到Survivor区或老年代Region。
并发标记周期:类似CMS,但不针对整个老年代。
混合回收:在并发标记周期后,G1既回收新生代Region,也回收一部分价值高的老年代Region(这就是名字的由来)。这是G1的核心阶段。
优点:
可预测的停顿:用户可以设置一个期望的停顿时间目标,G1会尽力在这个目标内完成垃圾回收。
高吞吐量与低延迟兼顾:整体上看性能表现均衡。
有效处理内存碎片:在回收过程中通过复制算法进行整理,减少了内存碎片。
缺点:
内存占用和运行时负载较CMS稍高。
适用场景:
几乎适用于所有场景,特别是:
内存较大的多核服务器(堆内存6GB以上效果显著)。
同时要求高吞吐量和低延迟的应用。
四、Maven核心机制详解:生命周期、依赖传递与冲突解决
1. 核心概念
(1) POM
定义:Maven 项目的核心配置文件,名为
pom.xml
,描述项目的基本信息、依赖、构建配置等。作用:
定义项目坐标(
groupId
,artifactId
,version
)。管理项目依赖(
<dependencies>
)。配置构建生命周期(
<build>
)。定义插件(
<plugins>
)。
(2) 坐标(Coordinates)
作用:唯一标识一个 Maven 项目或依赖,由三个关键属性组成:
groupId
:组织或公司名称(如org.apache
)。artifactId
:项目名称(如commons-lang3
)。version
:版本号(如3.12.0
)。
(3) 依赖(Dependencies)
作用:声明项目所需的外部库(JAR 文件)。
依赖范围(Scope):
compile
(默认):编译、测试、运行时都可用。test
:仅测试阶段可用(如 JUnit)。provided
:编译和测试可用,运行时由 JDK 或容器提供(如 Servlet API)。runtime
:运行时需要,但编译时不需要(如 JDBC 驱动)。system
:依赖本地文件(不推荐)。
(4) 生命周期(Lifecycle)
定义:Maven 构建过程分为三个生命周期:
clean
:清理项目(删除target
目录)。
default
:核心构建流程(编译、测试、打包等)。
site
:生成项目文档(如mvn site
)。
default
生命周期关键阶段:阶段
作用
validate
验证项目是否正确
compile
编译源代码
test
运行单元测试
package
打包(JAR/WAR)
verify
运行集成测试
install
安装到本地仓库
deploy
发布到远程仓库
(5) 插件(Plugins)
作用:Maven 本身不执行具体任务,而是通过插件完成(如编译、测试、打包等)。
常见插件:
maven-compiler-plugin
:编译 Java 代码。maven-surefire-plugin
:运行单元测试。maven-jar-plugin
:打包 JAR 文件。
2. 依赖传递与冲突解决
(1) 依赖传递原则
依赖传递性:如果 A 依赖 B,B 依赖 C,那么 A 会自动引入 C。
依赖调解原则:
最短路径优先:如果两个版本的依赖路径不同,选择路径最短的。
声明优先:如果路径长度相同,先声明的依赖优先。
(2) 依赖冲突解决
查看依赖树:
解决方案:
排除特定依赖:
显式指定版本:
使用
<dependencyManagement>
总结
核心概念 | 作用 |
---|---|
POM | 定义项目配置 |
坐标 | 唯一标识项目或依赖 |
依赖 | 管理外部库 |
生命周期 | 定义构建流程 |
插件 | 执行具体任务 |
依赖传递 | 自动引入间接依赖 |
冲突解决 | 排除或显式指定版本 |
Nexus 的核心功能
Nexus 是一种 Maven 仓库管理器,其核心功能可以概括为以下几点:
代理远程仓库:为企业内网提供一个本地缓存代理,当开发者请求一个公共库(如 Maven Central)时,Nexus 会从远程仓库下载并缓存到本地,后续相同的请求将直接从 Nexus 获取,速度极快。
托管私有仓库:用于存放企业内部的、不愿公开的私有组件(如公司内部的基础工具包、二方库等)。
仓库组:将多个仓库聚合为一个统一的访问地址,简化开发者的配置。
权限管理与安全:提供用户、角色、权限管理,保障私有依赖的访问安全。
稳定性与可靠性:降低对外网的依赖,即使外网仓库不可用,内部构建仍可依靠本地缓存继续进行。
仓库类型及其区别与应用场景
Nexus 主要有三种核心仓库类型,理解它们的区别是使用 Nexus 的关键。
仓库类型 | 功能描述 | 应用场景 | 比喻 |
---|---|---|---|
宿主仓库 | 存储本地生成的组件。你可以将自己项目构建产生的 JAR 包通过 | 存放公司内部项目的发布版本(Releases)和快照版本(Snapshots)。 | 公司的私人书架,专门存放自己编写的书籍和文档。 |
代理仓库 | 代理并缓存公共仓库。它本身不存储内容,而是指向一个远程仓库(如 Maven Central)。当首次请求某个依赖时,Nexus 会从远程拉取并缓存到本地。 | 代理 Maven Central、阿里云 等公共仓库,加速访问并提供稳定性。 | 公司的报刊亭,定期从外部(如邮局)取回报纸和杂志,员工需要时直接来亭子取,无需联系邮局。 |
组仓库 | 仓库的聚合器。它将多个宿主仓库和代理仓库组合起来,提供一个统一的访问地址。开发者只需要在项目的 | 统一访问入口。例如创建一个 |
为什么在企业开发中需要使用 Nexus 作为私有仓库?
一、提升开发效率:加速构建,节省资源
极速依赖下载(本地缓存代理)
显著节省带宽成本
二、保障开发稳定性:构建高可用,隔离风险
隔离公共仓库的不稳定性
提供单一可信源
三、加强安全与管控:保护资产,规范流程
统一管理私有组件
严格的权限访问控制
快照仓库:开发人员可以部署,但不能删除稳定版本。
发布仓库:只有项目经理或运维有权限部署,保证核心组件的稳定性。
只读权限:普通开发者只有下载权限。
安全扫描与漏洞审计
四、优化管理与协作:标准化流程,提升质量
规范化组件生命周期管理
Nexus 天然支持 SNAPSHOT
(快照版本,用于持续集成)和 RELEASE
(发布版本,用于稳定部署)的管理,使开发流程更加规范。
部署第三方非公开组件
对于一些无法从公共仓库获取的、需要购买授权的第三方商业组件(如 Oracle JDBC Driver),可以手动上传到 Nexus 的宿主仓库,从而纳入统一管理
五、三大范式的定义与应用例子
数据库设计的三大范式
为了更好的理解不遵守三大范式可能造成的种种问题,我们通过提前建立一个表格来更加直观地表示
学生学号 | 姓名 | 所属学院 | 学院地址 | 课程号 | 课程名称 | 成绩 |
---|---|---|---|---|---|---|
1001 | 小明 | 计算机学院 | 科技楼101 | C01 | 数据结构 | 90 |
1001 | 小明 | 计算机学院 | 科技楼101 | C02 | 操作系统 | 85 |
1002 | 小红 | 文学院 | 人文楼201 | C01 | 数据结构 | 95 |
1003 | 小张 | 计算机学院 | 科技楼101 | C03 | 计算机网络 | 88 |
第一范式(1NF):原子性
定义:数据库表中的每一列都是不可再分的最小数据单元(即确保每列具有原子性)。
要求:表中不能有集合、数组或记录嵌套记录的情况。每个字段都必须是单一值。
检查我们的表:它已经满足1NF,因为每个字段(学号、姓名、课程等)都是不可再分的原子值。
第二范式(2NF):消除部分依赖
前提:必须满足第一范式。
定义:要求数据库表中的每个非主属性必须完全依赖于整个主键,而不能只依赖于主键的一部分。
要求:当表的主键是复合主键时,所有非主键字段必须由整个主键共同决定,而不能只由主键中的某个字段决定。
分析我们的表:
主键:(学生学号,课程号)
非主属性:姓名、所属学院、学院地址、课程名称、成绩。
我们检查这些非主属性与主键的依赖关系:
成绩:完全依赖于整个主键。你需要同时知道是哪个学生和哪门课,才能确定成绩。
姓名、所属学院、学院地址:部分依赖于主键。它们只由 学生学号 决定,与课程号无关。例如,只要学号是1001,姓名就一定是“小明”,学院就一定是“计算机学院”,无论他选了什么课。
课程名称:部分依赖于主键。它只由 课程号 决定,与学生学号无关。课程号C01永远对应“数据结构”
不满足2NF导致的问题:
数据冗余:小明的“姓名、所属学院、学院地址”信息在他每选一门课后都重复存储一次。
更新异常:如果计算机学院搬到了“科技楼202”,需要修改所有“所属学院”为“计算机学院”的记录。如果漏改一条,就会导致数据不一致(同一个学院有两个地址)。
插入异常:如果一个新学院“法学院”刚成立,还没有学生入学选课,那么这条学院信息将无法插入到表中,因为缺少主键的一部分(学生学号和课程号)。
删除异常:如果学生1003只选了“计算机网络”一门课,现在他退选了这门课。当我们删除这条选课记录时,连带着“小张是计算机学院的学生”这个基本信息也被删除了。
第三范式(3NF):消除传递依赖
前提:必须满足第二范式。
定义:要求表中所有非主属性必须直接依赖于主键,而不能存在传递依赖。即:不能存在“A依赖于B,B依赖于主键,从而A间接依赖于主键”的情况。
要求:任何非主属性不得依赖于其他非主属性
不满足3NF导致的问题:
数据冗余:同一个学院的地址在每个该学院的学生记录中重复出现。
更新异常:计算机学院地址变更,仍需修改所有计算机学院学生的记录,否则会出现数据不一致。
插入异常:新成立一个“法学院”,但还没有招生(即没有学生学号),则无法将法学院及其地址信息插入学生表。
删除异常:如果文学院的学生小红毕业,删除她的记录后,文学院及其地址信息也会从数据库中消失。
七、MySQL 中索引的作用与原理
MySQL 索引详解
一、索引的核心作用
索引是数据库的"目录",通过预排序+快速定位机制加速查询,其核心价值体现在:
查询加速:将全表扫描的O(n)复杂度降至O(log n)
排序优化:避免filesort临时排序
约束保障:唯一索引实现数据唯一性约束
二、索引实现原理
B+树索引(主流实现)
数据结构:多路平衡搜索树,InnoDB默认使用
特点:
非叶子节点只存键值和指针(约1200个分叉)
叶子节点形成双向链表(范围查询高效)
所有数据存在叶子节点(3层树可存2000万数据)
检索过程:根节点,非叶子节点,叶子节点三级跳
哈希索引
原理:key-value式散列存储(如Memory引擎)
特点:
精确查询O(1)时间复杂度
不支持范围查询和排序
存在哈希冲突问题
全文索引
实现:倒排索引结构(FULLTEXT类型)
特性:
支持
MATCH AGAINST
语法默认最小词长4字符(innodb_ft_min_token_size)
停用词过滤机制
三、索引类型对比表
类型 | 存储引擎 | 是否有序 | 支持查询类型 | 典型场景 |
---|---|---|---|---|
B+树 | InnoDB/MyISAM | 是 | 全功能 | 主键、普通索引 |
Hash哈希 | Memory/NDB | 否 | 仅等值查询 | 缓存表、临时表 |
全文 | InnoDB/MyISAM | 否 | 文本搜索 | 文章搜索 |
四、索引的优缺点
优势:
查询速度提升巨大,大幅减少服务器排序操作,唯一索引保证数据完整性
代价:
写操作变慢,存储空间增加,维护成本
五、索引创建策略
适合创建场景:
WHERE条件高频字段,连接查询的关联字段,排序字段,分组字段,高区分度列
避免创建场景:
频繁更新的字段,区分度低的列,TEXT/BLOB大字段,数据量小的表
八、MySQL索引与慢查询优化:索引原理、使用场景与SQL性能调优
一、慢查询日志核心作用
慢查询日志是MySQL内置的性能诊断工具,用于记录执行时间超过阈值的SQL语句。
性能问题发现,捕获低效SQL(占数据库70%以上性能问题);SQL优化依据,提供真实的优化靶点;系统监控,长期记录可分析性能趋势
二、日志开启与配置
先看一下慢查询的状态
接下来,开启慢查询
此时的配置时临时生效,如果需要永久生效,需要更改配置
编辑 /etc/my.cnf
或 /etc/my.cnf.d/server.cnf
修改后重启MySQL服务:sudo systemctl restart mysqld
使用 tail
命令实时监控新产生的慢SQL
五、SQL优化核心手段
1. 索引优化
2. SQL重写
3. 分页优化
4. 连接查询优化
5. 避免全表扫描