面试题总结二
1.mybatis三个范式
- 第一范式:表中字段不能再分,每行数据都是唯一的
- 第二范式:满足第一范式,非主键字段只依赖于主键
- 第三范式:满足第二范式,非主键字段没有传递依赖
2.MySQL数据库引擎有哪些
- InnoDB(默认):支持事务,外键约束,行级锁,mvcc,高并发
- MyISAM:不支持事务和外键约束,查询效率高
- Memery:数据存储到内存中,读写极快,查询块
3.数据库事务–ACID
原子性,一致性,隔离性,持久性
4.索引是什么,怎么用
索引是数据库中用于快速定位数据的一种数据结构,类似于书籍的目录。合理使用索引可以显著提升查询效率,但错误的索引策略会导致性能下降。
原理:通过索引快速定位数据位置,避免全表扫描。常见类型有 B-Tree、哈希、全文索引等。
5.SQL优化的手段有哪些
- 查询语句优化
- 避免全表扫描
问题:SELECT * FROM users WHERE age > 20(无索引时全表扫描)。
优化:为age字段添加索引,改为SELECT id, age FROM …(覆盖索引)。 - 减少子查询
问题:SELECT * FROM orders WHERE user_id IN (SELECT id FROM users WHERE gender=‘女’)。
优化:改用JOIN
- 索引优化
- 表结构优化
- 垂直拆分:将不常用字段拆分到单独表,减少主表数据量
- 水平拆分(分库分表)按时间或 ID 范围拆分大表
- 数据库参数调整
- InnoDB 缓冲池大小
- 查询缓存
6. drop,delete,truncate的区别
- DROP DROP TABLE table_name; 删除整个表结构及数据,释放存储空间。
- DELETE DELETE FROM table_name WHERE condition; 删除符合条件的记录,可带 WHERE 子句。
- TRUNCATE TRUNCATE TABLE table_name; 快速删除表中所有数据,保留表结构。
7.什么是视图
视图(View) 是一种虚拟表,它基于 SQL 查询语句定义,并不实际存储数据。视图像是一个窗口,通过它可以查看或操作数据库中的特定数据,而无需直接访问底层表。
视图是一个预定义的 SQL 查询,存储在数据库中作为对象,但不存储实际数据。每次查询视图时,数据库会动态执行其定义的 SQL 语句并返回结果。
- 作用:
简化复杂查询:将常用的复杂查询封装为视图,简化使用。
数据安全:通过视图暴露部分数据,隐藏敏感字段(如用户密码)。
逻辑隔离:屏蔽底层表结构变化,提供稳定的数据接口。
权限控制:仅授权用户访问视图,而非直接操作表。
8.什么是内连接,左外连接,右外连接
9.并发事务带来哪些问题
脏读,幻读,不可重复读,丢失更新
10.事务隔离级别有哪些,MySQL的默认隔离级别是
数据库的事务隔离级别是控制并发事务之间可见性的机制,用于平衡数据一致性和系统性能。不同隔离级别解决不同的并发问题(如脏读、不可重复读、幻读)。
读未提交:脏读
读已提交:幻读,不可重复读
可重复读:幻读
串行化:最高隔离级别,强制事务串行执行,避免所有并发问题(脏读、不可重复读、幻读、丢失更新)
11.MVCC
MVCC(Multi-Version Concurrency Control,多版本并发控制)是数据库实现高并发的核心技术,通过保存数据的多个版本,让读写操作可以并发执行而互不阻塞。
- MVCC 的核心思想
- 读写分离:
读操作不获取锁,直接读取历史版本数据,避免与写操作互斥。 - 无锁读:
读操作不会阻塞写操作,写操作也不会阻塞读操作,提升并发性能。 - 版本管理:
每个数据行维护多个版本,通过事务 ID 和时间戳标识版本顺序。
12.大表如何优化?
- 限定数据的范围
- 读写分离
- 垂直分区
- 水平分区
13.分库分表后,id主键如何处理
在数据库分库分表后,传统的自增主键(如 MySQL 的AUTO_INCREMENT)无法直接保证全局唯一性,需要设计新的 ID 生成方案。
- UUID(通用唯一识别码)
- 数据库自增 ID(分布式 ID 表)
- Redis 生成 ID
14.MySQL中varchar和char区别
特性 VARCHAR CHAR
存储方式 变长存储(动态分配空间) 定长存储(固定分配空间)
存储空间 实际字符串长度 + 1-2 字节(记录长度) 固定为定义的长度(不足补空格)
最大长度 65,535 字节(受行最大长度和字符集限制) 0-255 字符
存储示例 VARCHAR(10)存储’abc’ → 占用 4 字节 CHAR(10)存储’abc’ → 占用 10 字节
15.int(11)代表什么含义
括号内的数字(11) 与存储范围无关,仅表示 显示宽度
jvm知识点汇总
JVM(Java Virtual Machine)是 Java 平台的核心,负责将字节码翻译成机器码并执行。
- JVM 整体架构
JVM 由三个主要部分组成:
- 类加载子系统(Class Loading Subsystem)
负责加载 .class 文件到内存。 - 运行时数据区(Runtime Data Areas)
包含方法区、堆、栈、本地方法栈、程序计数器等内存区域。 - 执行引擎(Execution Engine)
解释 / 编译字节码为机器码并执行,包含即时编译器(JIT)和垃圾回收器。
- 类加载流程
- 加载(Loading)
通过类加载器将 .class 文件加载到内存。 - 链接(Linking)
验证(Verification):确保字节码符合 JVM 规范。
准备(Preparation):为静态变量分配内存并设置初始值。
解析(Resolution):将符号引用转换为直接引用。 - 初始化(Initialization)
执行类构造器 () 方法,初始化静态变量和静态代码块。
- 内存区域
- 堆(Heap)
所有对象实例和数组分配的内存区域。
线程共享,是垃圾回收的主要区域(GC 堆)。
可分为新生代(Eden、Survivor 区)和老年代。 - 方法区(Method Area)
存储类信息、常量、静态变量、即时编译后的代码等。
线程共享,JDK 8 后称为元空间(Metaspace),使用本地内存。 - 栈(JVM Stack)
每个线程私有,存储方法调用的栈帧(局部变量表、操作数栈、动态链接、方法出口)。
抛出 StackOverflowError(栈深度超过限制)或 OutOfMemoryError(栈扩展失败)。 - 本地方法栈(Native Method Stack)
为 Native 方法服务,如使用 C 语言实现的方法。 - 程序计数器(Program Counter Register)
记录当前线程执行的字节码行号,线程私有。
1.jvm类加载和卸载
- 类加载的生命周期
类从被加载到虚拟机内存到卸载,经历以下阶段:
加载 → 验证 → 准备 → 解析 → 初始化 → 使用 → 卸载 - 双亲委派模型工作流程
当类加载器收到加载请求时,先委派给父类加载器尝试加载。
父类加载器继续向上委派,直到启动类加载器。
若父类加载器无法加载(查找范围未找到),则子类加载器尝试加载 - 类卸载的条件
JVM 中的类被卸载需同时满足以下三个条件:
该类的所有实例已被垃圾回收。
加载该类的类加载器已被垃圾回收。
该类的 java.lang.Class 对象没有被任何地方引用。
2.方法区和本地方法栈的区别
方法区 本地方法栈
存储内容 类信息、常量、静态变量、JIT 编译后的代码 本地方法(Native Method)的调用栈帧
线程共享性 所有线程共享 每个线程独立拥有
内存位置 JDK 7 前:堆的永久代
JDK 8 后:本地内存(元空间) 通常在 JVM 内存区域内(HotSpot 将其与虚拟机栈合并)
生命周期 与 JVM 生命周期一致(除非使用自定义类加载器) 与线程生命周期一致
3. 堆和栈的区别
特性 堆(Heap) 栈(Stack)
存储对象 实例和数组 方法栈帧
线程安全 需同步机制 天然线程安全
分配方式 动态(运行时) 静态(编译时)
回收方式 GC 自动回收 方法结束后自动释放
性能 较慢 极快
4.什么时候触发Full GC
- 新生代对象经过多次 Minor GC 后仍存活,会晋升到老年代。若老年代空间不足,触发 Full GC。
- 清除算法(如 CMS)会产生内存碎片,当无法为大对象分配连续空间时,触发 Full GC 进行内存整理。
-
如何减少 Full GC 频率?
优化堆内存配置
增大堆空间,合理分配新生代和老年代比例。
避免大对象和长生命周期对象
减少直接进入老年代的大对象,降低晋升压力。
选择合适的 GC 收集器
如 G1 适合大内存场景,CMS 适合低延迟场景。Full GC 的触发通常与内存分配失败、空间不足或碎片问题相关。频繁的 Full GC 会严重影响系统性能,因此需要通过监控工具(如 GCEasy、GCViewer)分析 GC 日志,针对性地调整堆大小、收集器类型或代码逻辑。
5.java被称为平台无关的编程语言原因?
Java 源代码(.java)经编译器编译后生成字节码文件(.class),而非直接生成平台特定的机器码。
每个平台(Windows、Linux、macOS 等)都有对应的 JVM 实现,负责将字节码翻译成具体平台的机器码并执行。
6.什么是jvm?
JVM(Java Virtual Machine)即Java 虚拟机,是 Java 平台的核心组件,负责执行 Java 字节码,实现 “一次编写,到处运行” 的跨平台特性。它是一个抽象的计算机,通过软件模拟实现了计算机的基本功能(如内存管理、指令执行、线程调度等)。
7.描述jvm加载class文件的原理机制
- 类加载的时机
JVM 遵循按需加载原则,在以下情况发生时会触发类的加载:
- 创建类的实例(new操作)
- 调用类的静态方法或访问静态字段
- 使用反射(如Class.forName())
- 初始化子类时会先触发父类加载
- JVM 启动时指定的主类(含main方法的类)
- 双亲委派模型
8. 对象分配规则
- 对象优先在 Eden 区分配
原理:大多数情况下,新创建的对象会被分配到新生代的Eden 区。
触发 GC:当 Eden 区空间不足时,会触发Minor GC(新生代垃圾回收),存活的对象会被移至Survivor 区。 - 大对象直接进入老年代
- 长期存活的对象进入老年代
- 空间分配担保
发生 Minor GC 前,JVM 会检查老年代最大可用连续空间是否大于新生代所有对象总空间。
若成立,Minor GC 安全;否则,查看-XX:HandlePromotionFailure(JDK 6 + 默认允许担保失败)。
若允许,检查老年代最大可用连续空间是否大于历次晋升到老年代对象的平均大小:
是:尝试 Minor GC(可能失败)。
否:触发 Full GC。
9.java对象创建过程
-
类加载检查:当 JVM 遇到new指令时,首先检查指令的参数是否能在常量池中定位到一个类的符号引用,并验证这个类是否已被加载、链接和初始化。如果没有,则先执行类的加载过程(见前文类加载机制)
-
分配内存
方式:根据堆内存是否规整,有两种分配方式:
指针碰撞(Bump the Pointer):若内存规整(用过的内存放一边,空闲的放另一边),通过移动指针分配内存。
空闲列表(Free List):若内存不规整,JVM 维护一个记录可用内存块的列表,从中分配。 -
内存初始化
零值初始化:分配到的内存空间初始化为零值(如int为 0,引用类型为null)。
作用:保证对象的实例字段在 Java 代码中可以不赋初始值就直接使用。
10.java对象生命周期
- 创建阶段:
类加载检查:JVM 检查类是否已加载,未加载则触发类加载机制。
内存分配:在堆中为对象分配内存,可能使用 TLAB(线程本地分配缓冲区)优化。
初始化零值:所有字段初始化为默认值(如int为 0,引用为null)。
设置对象头:存储哈希码、分代年龄、锁状态等信息。
执行构造方法:按顺序初始化实例变量和执行构造代码。 - 应用阶段
对象创建后进入应用阶段,此时对象具有以下特征:
可达性:至少有一个引用指向该对象(如栈中的局部变量、静态变量等)。
活跃状态:对象在程序中被使用,参与各种业务逻辑。
内存占用:对象在堆中占据空间,其字段值可能被修改。 - 不可达阶段(Unreachable)
当对象不再被引用时,进入不可达阶段,常见原因:
引用置为null:如person = null。
局部变量超出作用域:方法执行结束后,局部变量引用的对象可能不可达。
对象被集合移除:如list.remove(person)。
弱引用或软引用被 GC 回收:当内存不足时,JVM 会回收这些引用关联的对象。 - 可回收阶段(Finalizable)
当对象不可达时,GC 会标记该对象,并检查是否重写了finalize()方法:
未重写finalize():对象直接进入可回收状态。
重写了finalize():对象会被放入F-Queue队列,由 Finalizer 线程执行finalize()方法(仅执行一次)。
注意:finalize()性能差且不可靠,不推荐使用,建议用try-with-resources或AutoCloseable替代。 - 收集阶段(Collected)
Minor GC:对象在 Eden 区创建,当 Eden 区满时触发 Minor GC,存活的对象被移至 Survivor 区。
晋升老年代:对象在 Survivor 区经历多次 GC 后(默认 15 次),晋升到老年代。
Full GC:老年代空间不足时触发 Full GC,回收整个堆的垃圾对象。 - 终结阶段(Finalized)
当finalize()方法执行完毕(如果有)或对象未重写finalize(),对象进入终结阶段。
此时对象的内存空间已被标记为可回收,但尚未被实际释放。 - 对象内存回收
GC 算法:标记 - 清除、标记 - 整理、复制算法等(取决于 JVM 的 GC 策略)。
分代回收:新生代(Eden、Survivor)和老年代采用不同的回收策略。
内存分配担保:老年代需担保新生代对象晋升的空间。
11.jvm的永久代中会发生垃圾回收吗
在 JVM 中,永久代(PermGen)会发生垃圾回收,但回收条件较为苛刻,且回收效率较低。
- 永久代的垃圾回收对象
永久代主要存储类元数据(如类结构、方法字节码)、常量池和静态变量。 - 触发永久代 GC 的条件
显式调用:执行System.gc()可能触发 Full GC,包含永久代回收。
空间不足:永久代空间满时(如达到-XX:MaxPermSize限制),触发 Full GC。
CMS GC:使用 CMS 收集器时,若CMSClassUnloadingEnabled开启,会在 CMS 周期中回收永久代。
12.你知道哪些垃圾收集算法吗
- 标记 - 清除算法(Mark-Sweep)
流程:
标记阶段:从 GC Roots 出发,标记所有可达对象。
清除阶段:回收未被标记的对象,释放内存空间。 - 标记 - 整理算法(Mark-Compact)
流程:
标记阶段:同标记 - 清除算法,标记所有可达对象。
整理阶段:将存活对象向一端移动,然后直接清理边界外的内存。 - 复制算法(Copying)
流程:
将内存分为Eden 区和两个Survivor 区(通常比例为 8:1:1)。
新对象分配在 Eden 区,当 Eden 区满时,触发 Minor GC。
存活的对象被复制到其中一个 Survivor 区(如 S0),清空 Eden 区。
下次 GC 时,将 Eden 区和 S0 区的存活对象复制到另一个 Survivor 区(S1),然后清空 Eden 和 S0。
对象在 Survivor 区中多次存活后(默认 15 次),晋升到老年代。 - 分代收集算法(Generational Collection)
核心思想:根据对象存活周期将内存分为新生代和老年代,分别采用不同的回收算法。
新生代:对象存活率低,使用复制算法(Minor GC 频繁)。
老年代:对象存活率高,使用标记 - 清除或标记 - 整理算法(Full GC 较少)。
应用:几乎所有现代 JVM(如 HotSpot)都采用分代收集策略。
13.调优命令有哪些
JVM 调优是优化 Java 应用性能的关键环节,涉及内存分配、垃圾回收、线程管理等多个方面。
GC 调优相关参数
-
内存分配参数
bash
-Xms512m # 初始堆大小
-Xmx1g # 最大堆大小
-XX:NewSize=256m # 新生代初始大小
-XX:MaxNewSize=512m # 新生代最大大小
-XX:SurvivorRatio=8 # Eden:Survivor = 8:1
-XX:MetaspaceSize=128m # 元空间初始大小(JDK 8+)
-XX:MaxMetaspaceSize=256m # 元空间最大大小 -
垃圾收集器选择
bash
-XX:+UseSerialGC # 串行收集器(新生代+老年代)
-XX:+UseParallelGC # 并行收集器(新生代)
-XX:+UseParallelOldGC # 并行收集器(老年代)
-XX:+UseConcMarkSweepGC # CMS收集器(老年代)
-XX:+UseG1GC # G1收集器
-XX:+UseZGC # ZGC收集器(JDK 11+) -
GC 日志参数
bash
-verbose:gc # 输出GC简要信息
-XX:+PrintGCDetails # 输出GC详细信息
-XX:+PrintGCDateStamps # 输出GC时间戳
-XX:+PrintHeapAtGC # 输出GC前后的堆信息
-Xloggc:gc.log # 指定GC日志文件
JVM 调优需要结合工具监控和参数调整,常见步骤包括:
- 监控:使用jstat、jmap、VisualVM 等工具收集性能数据。
- 分析:通过 GC 日志、堆转储、线程快照定位问题。
- 调整:根据分析结果调整内存分配、GC 策略等参数。
- 验证:重新运行应用,验证调优效果。
14.Minor GC与Full GC分别在什么时候发生
- Minor GC(新生代 GC)
- 作用范围
仅针对新生代(Eden 区和 Survivor 区)进行垃圾回收。
目标:回收新生代中不再被引用的对象,释放内存空间。 - 触发条件
Eden 区空间不足
当 Eden 区无法容纳新创建的对象时,触发 Minor GC。此时,存活对象会被转移到 Survivor 区(或老年代,若对象年龄足够大)。
动态年龄判定规则
当 Survivor 区中相同年龄的对象大小总和超过 Survivor 区的 50% 时,年龄大于等于该年龄的对象会直接进入老年代。
显式调用System.gc()
虽然System.gc()会触发 Full GC,但在某些场景下(如使用 Serial 收集器时),可能先触发 Minor GC。
- Full GC(全堆 GC)
- 作用范围
针对整个堆内存(新生代、老年代、元空间 / 永久代)进行垃圾回收。
目标:回收老年代和元空间中的垃圾对象,处理跨代引用。 - 触发条件
老年代空间不足
当老年代无法容纳从新生代晋升的对象,或直接在老年代分配大对象(如-XX:PretenureSizeThreshold设置的大对象)时,触发 Full GC。
元空间(MetaSpace)不足(JDK 8+)
元空间用于存储类元数据、常量池等,当空间不足时(如动态生成大量类),触发 Full GC 回收废弃的类元数据。
显式调用System.gc()
调用System.gc()或Runtime.getRuntime().gc()时,会触发 Full GC(可通过-XX:+DisableExplicitGC禁用)。
Minor GC 时的 “担保失败”
新生代 GC 时,若老年代剩余空间不足以容纳所有新生代存活对象,会先尝试触发 Full GC(“安全担保” 机制)。
调用jmap -dump:live等命令
生成堆转储文件时,可能触发 Full GC(仅收集存活对象)。
1.什么是spring?
Spring 是一个开源的 Java 企业级应用开发框架。它旨在简化企业级应用开发,提供全面的基础设施支持,帮助开发者构建高效、可维护的应用程序。
- Spring 的核心优势
IoC(控制反转)与 DI(依赖注入)
通过容器管理对象的生命周期和依赖关系,降低代码耦合度。
AOP(面向切面编程)
支持声明式事务、日志、安全等横切关注点,将通用逻辑与业务逻辑分离。
1.2为什么要用Spring Boot?
Spring Boot 是构建现代 Java 应用的首选框架,它通过自动化配置和约定优于配置(Convention Over Configuration)的理念,彻底简化了 Spring 应用的开发和部署流程。
核心优势
- 快速搭建项目:Starters 依赖管理,内嵌容器
- 自动化配置:零 XML 配置
- 微服务友好:与 Spring Cloud 无缝集成
特性 传统 Spring Spring Boot
依赖管理 手动配置大量依赖及版本 Starter 自动管理依赖
配置方式 大量 XML 或 Java 配置 自动配置 + 少量属性文件
部署方式 需部署 WAR 到外部容器 内嵌容器,直接运行 JAR
监控与运维 需手动集成监控组件 Actuator 开箱即用
开发效率 配置繁琐,启动时间长 快速启动,支持热部署
微服务支持 需额外集成多种组件 与 Spring Cloud 无缝集成
2.spring Boot的核心注解是那个,它主要由哪几个注解组成
Spring Boot 的核心注解是@SpringBootApplication,它是一个组合注解,主要由以下三个注解组成:@SpringBootConfiguration,@EnableAutoConfiguration,@ComponentScan
3.运行springBoot有哪几种方式
- 直接运行主类
条件:IDE(如 IntelliJ IDEA、Eclipse)已安装并配置好 JDK。
步骤:
打开包含main方法的主类(带有@SpringBootApplication注解)。
右键点击main方法,选择 “Run” 或 “Debug”。
2.使用 Maven 插件
命令:mvn spring-boot:run - 打包为可执行 JAR:java -jar myapp-0.0.1-SNAPSHOT.jar
4.如何理解SpringBoot中的starters
在 Spring Boot 中,Starters是一种依赖管理的简化机制,用于快速集成特定功能模块,避免手动配置大量依赖和版本冲突。
5.如何在SpringBoot启动的时候运行一些特定的代码?
PostConstruct:Bean 初始化后立即执行。
ApplicationListener:应用上下文刷新完成后执行。
ApplicationStartedEvent:应用启动过程中触发。
CommandLineRunner/ApplicationRunner:应用上下文完全初始化后执行。
ApplicationReadyEvent:应用完全就绪后触发。
6.springboot需要独立的容器运行吗?
Spring Boot 可以独立运行,也可以部署到外部容器,具体取决于应用类型和部署需求。
- 内嵌容器(默认方式)
Spring Boot 的默认模式是内嵌容器,无需独立的 Servlet 容器(如 Tomcat、Jetty) - 部署到外部容器
若需要将 Spring Boot 应用部署到独立容器(如 Tomcat、WebLogic),需进行以下调整:
修改打包方式,排除内嵌容器依赖
将 pom.xml 中的 改为 war
7.Spring Boot中的监视器是什么?
在 Spring Boot 中,Actuator 是核心的监控与管理组件,它提供了生产级别的功能(如健康检查、指标收集、配置信息、环境信息、日志管理、审计等),帮助开发者在应用运行时监控和管理应用状态。
8.如何使用Spring Boot实现异常处理?
使用 @ControllerAdvice + @ExceptionHandler(推荐)
9.Spring Boot常用的starter有哪些
核心基础类:spring-boot-starter、spring-boot-starter-test
Web 开发类:spring-boot-starter-web、spring-boot-starter-validation
数据访问类:spring-boot-starter-data-jpa、spring-boot-starter-data-mongodb、spring-boot-starter-data-redis
安全类:spring-boot-starter-security
10.Spring Boot实现热部署有哪几种方式
- 使用 DevTools
原理:Spring Boot DevTools 通过两个类加载器实现:基础类加载器(加载不会改变的类,如第三方依赖)和重启类加载器(加载应用代码)。当代码变更时,仅重启类加载器重新加载,大幅缩短重启时间。 - 使用 JRebel(商业工具)
- 使用 IDE 内置热部署(轻量级)
- 使用 Docker 实现热部署
11.如何理解Spring Boot配置加载顺序
后加载的配置优先
Spring Boot 按特定顺序加载配置源,后加载的配置会覆盖先加载的相同属性。
外部配置优先于内部配置
外部配置(如命令行参数、环境变量)优先级高于内部配置(如 application.properties)。
多环境配置优先级
特定环境配置(如 application-prod.properties)优先于通用配置(如 application.properties)。
12.Spring Boot的核心配置文件有哪几个?他们的区别是什么?
- 核心配置文件类型 application.properties/application.yml全局通用配置,适用于所有环境。
- application-{profile}.properties/application-{profile}.yml全局通用配置,适用于所有环境。
- bootstrap.properties/bootstrap.yml优先加载的配置,用于引导应用上下文(如配置中心、服务发现)
13.如何集成Spring Boot和ActiveMQ?
在 Spring Boot 中集成 ActiveMQ(Apache ActiveMQ)可以实现高效的消息传递,支持异步通信、解耦服务等场景。
- 环境准备:添加依赖、配置 ActiveMQ 连接信息
- 消息生产者(Producer):创建消息发送服务
- 消息消费者(Consumer):创建消息监听