JMM
mindmap
root((JMM<br/>Java Memory Model))
本质
并发访问共享变量的规则
不是JVM物理内存分区
解决线程间可见性与有序性问题
核心目标
原子性
可见性
有序性
抽象模型
主内存
存共享变量
工作内存
每个线程私有副本
线程先读副本再写回主内存
问题来源
缓存不一致
指令重排
并发交错执行
关键机制
volatile
保证可见性
禁止部分指令重排
不能保证复合操作原子性
synchronized
保证原子性
保证可见性
保证有序性
final
构造完成后安全发布
对final字段有特殊可见性保障
Happens-Before
程序次序规则
锁规则
volatile规则
start规则
join规则
传递性
重排序
编译器优化
CPU乱序执行
单线程遵守as-if-serial
多线程可能出问题
经典场景
volatile标志位
DCL单例
i++线程不安全
JUC
mindmap
root((JUC<br/>Java Util Concurrent))
本质
Java并发编程工具箱
高层并发组件
覆盖任务执行 锁 容器 协作 异步
包结构
java.util.concurrent
java.util.concurrent.locks
java.util.concurrent.atomic
任务执行
Executor
ExecutorService
ScheduledExecutorService
ThreadPoolExecutor
Future
锁体系
Lock
ReentrantLock
ReadWriteLock
ReentrantReadWriteLock
Condition
底层支撑
AQS
LockSupport
CAS
volatile
原子类
AtomicInteger
AtomicLong
AtomicReference
AtomicStampedReference
LongAdder
并发容器
ConcurrentHashMap
ConcurrentLinkedQueue
CopyOnWriteArrayList
ConcurrentSkipListMap
ConcurrentSkipListSet
阻塞队列
BlockingQueue
ArrayBlockingQueue
LinkedBlockingQueue
PriorityBlockingQueue
SynchronousQueue
同步器
CountDownLatch
Semaphore
CyclicBarrier
Phaser
异步与并行
ForkJoinPool
ForkJoinTask
CompletableFuture
CompletionStage
面试主线
线程池参数与拒绝策略
AQS原理
CAS与ABA
ConcurrentHashMap
BlockingQueue生产者消费者
CountDownLatch与CyclicBarrier区别
CompletableFuture链式编排
设计模式
mindmap
root((设计模式 Design Patterns))
设计目标
提高可维护性
提高可复用性
提高可扩展性
降低耦合
提升沟通效率
设计原则
SOLID
SRP["单一职责原则 SRP
一个类只做一类事"]
OCP["开闭原则 OCP
对扩展开放 对修改关闭"]
LSP["里氏替换原则 LSP
子类可替换父类"]
ISP["接口隔离原则 ISP
接口要小而专"]
DIP["依赖倒置原则 DIP
面向抽象编程"]
其他原则
CARP["合成复用原则
多用组合 少用继承"]
LoD["迪米特法则
只和直接朋友通信"]
分类
创建型模式
核心["关注对象怎么创建"]
简单工厂
工厂方法
抽象工厂
单例
建造者
原型
结构型模式
核心["关注类和对象如何组合"]
适配器
代理
装饰器
外观
桥接
组合
享元
行为型模式
核心["关注对象如何协作和分配职责"]
观察者
责任链
策略
状态
模板方法
命令
迭代器
中介者
备忘录
访问者
解释器
创建型高频
工厂模式家族
简单工厂
优点["创建逻辑集中"]
缺点["新增产品要改工厂
违反开闭原则"]
工厂方法
优点["扩展新产品更方便
符合开闭原则"]
缺点["类数量增加"]
抽象工厂
核心["创建一整套产品族"]
优点["同一风格产品统一切换"]
缺点["新增产品等级结构困难"]
单例模式
核心["一个类只有一个实例"]
写法
饿汉式
懒汉式
同步方法懒汉式
DCL["双重检查锁 DCL"]
静态内部类["推荐"]
枚举单例["推荐"]
关注点
线程安全
懒加载
防反射破坏
防反序列化破坏
结构型高频
适配器模式
核心["接口不兼容时做转换"]
角色
Target["目标接口"]
Adaptee["被适配者"]
Adapter["适配器"]
实现
类适配器["继承实现"]
对象适配器["组合实现 更推荐"]
代理模式
核心["控制对目标对象的访问"]
作用
权限控制
日志
事务
延迟加载
远程调用
Java实现
静态代理
JDK动态代理
CGLIB代理
装饰器模式
核心["不改原类前提下动态增强功能"]
对比代理
装饰器更强调功能增强
代理更强调控制访问
行为型高频
观察者模式
核心["一对多通知机制"]
适用
事件发布订阅
消息通知
状态变化广播
责任链模式
核心["多个处理器串成链逐个处理"]
适用
过滤器链
拦截器链
审批流
策略模式
核心["封装可替换算法"]
优点
消除大量 if else
算法可自由切换
符合开闭原则
适用
支付方式
促销计算
负载均衡
状态模式
核心["状态不同 行为不同"]
适用
订单状态流转
工作流状态机
对比策略
策略["重点在算法替换"]
状态["重点在状态驱动行为变化"]
面试回答主线
第一步["先说属于哪一类模式"]
第二步["再说解决什么问题"]
第三步["讲核心角色和结构"]
第四步["补优缺点"]
第五步["结合框架或项目举例"]
框架里的影子
Spring
工厂["BeanFactory"]
代理["AOP 事务"]
观察者["事件机制"]
JDK
单例["Runtime"]
工厂["Calendar getInstance"]
迭代器["Iterator"]
Netty
责任链["Pipeline"]
Dubbo
代理
装饰器
策略
责任链
API
输入输出&字符串
mindmap
root((输入输出与字符串))
输入处理
Scanner
next
nextInt
nextLine
常见坑
nextLine吞换行
BufferedReader
readLine
配合StringTokenizer
性能高于Scanner
StringTokenizer
分词处理
高效输入拆分
输出处理
System.out
print
println
printf
格式化输出
%d %s %f
String基础
创建方式
字面量
new String
常用方法
length
charAt
equals
compareTo
indexOf
lastIndexOf
contains
截取与拼接
substring
concat
判断类
startsWith
endsWith
isEmpty
StringBuilder
可变字符串
append
insert
delete
reverse
toString
应用
高频拼接
回文处理
StringBuffer
线程安全
性能较低
使用较少
字符数组
char
toCharArray
new String(char)
应用
双指针
原地修改
转换操作
字符串转数字
Integer.parseInt
Long.parseLong
Double.parseDouble
数字转字符串
String.valueOf
Integer.toString
字符转换
Character
isDigit
isLetter
分割与替换
split
正则分割
replace
replaceAll
常见技巧
去空格
trim
大小写转换
toLowerCase
toUpperCase
字符频率统计
Map结合String
数组和工具类
mindmap
root((数组与工具类))
数组基础
定义与初始化
int
new int[n]
静态初始化
访问与遍历
for循环
增强for
下标访问
多维数组
二维数组
不规则数组
Arrays工具类
排序
sort
基本类型排序
对象排序
自定义Comparator
查找
binarySearch
前提有序
返回插入点规则
填充
fill
拷贝
copyOf
copyOfRange
转字符串
toString
deepToString
比较
equals
deepEquals
System工具
数组拷贝
arraycopy
高性能native方法
浅拷贝
时间计算
currentTimeMillis
nanoTime
排序技巧
基本排序
升序默认
自定义排序
lambda表达式
Comparator接口
二维数组排序
按某列排序
TopK问题
排序解法
二分查找
手写模板
左边界
右边界
API方式
Arrays.binarySearch
常见场景
查找目标值
查找插入位置
前缀和
一维前缀和
prefixi=sum[0,i)
二维前缀和
应用
区间求和
子数组问题
差分数组
原理
区间更新
构造
diff数组
应用
批量区间修改
常见技巧
数组反转
双指针交换
滑动窗口
左右指针
双指针
对撞指针
快慢指针
离散化
排序+去重+映射
易错点
越界问题
index<length
binarySearch误用
未排序数组
浅拷贝问题
多维数组坑
集合框架
mindmap
root((集合框架))
总体结构
Collection
List
Set
Map
键值对结构
Iterable
for-each基础
List体系
ArrayList
底层结构
动态数组
特点
随机访问快
插入删除慢
常用API
add
get
set
remove
扩容机制
1.5倍扩容
LinkedList
底层结构
双向链表
特点
插入删除快
查询慢
常用API
addFirst
addLast
removeFirst
兼容Deque
Set体系
HashSet
底层
HashMap
特点
无序
不重复
判重机制
hashCode+equals
TreeSet
底层
红黑树
特点
有序
排序方式
Comparable
Comparator
LinkedHashSet
特点
保持插入顺序
Map体系
HashMap
底层
数组+链表+红黑树
核心机制
hash扰动
位运算定位
常用API
put
get
remove
containsKey
高频场景
计数
映射关系
TreeMap
底层
红黑树
特点
有序Map
LinkedHashMap
特点
维护顺序
LRU基础
Queue与Deque
Queue
接口
offer
poll
peek
应用
BFS
Deque
双端队列
addFirst
addLast
pollFirst
pollLast
实现
ArrayDeque
应用
单调队列
滑动窗口
PriorityQueue
本质
堆结构
特点
默认小顶堆
常用API
offer
poll
peek
自定义排序
Comparator
应用
TopK问题
贪心算法
Collections工具类
排序
sort
反转
reverse
查找
binarySearch
最大最小
max
min
频率统计
frequency
常见刷题模式
去重
Set
计数
Map
分组
Map+List
滑动窗口
Map+Deque
BFS
Queue
TopK
PriorityQueue
易错点
HashMap遍历
entrySet优于keySet
判重问题
equals未重写
并发问题
非线程安全
null处理
HashMap允许null
TreeMap不允许
数学与位运算
mindmap
root((数学与位运算))
Math工具类
常用方法
abs
max
min
pow
sqrt
ceil
floor
round
随机数
random
应用场景
数值处理
几何计算
位运算基础
基本操作
按位与
按位或
按位异或
按位取反
左移
右移
无符号右移
核心性质
异或同数得零
异或零得本身
满足交换律
满足结合律
位运算技巧
判断奇偶
与一判断最低位
清除最低位的一
与上减一
获取最低位的一
与上相反数
判断是否为二的幂
与上减一后为零
交换两个数
异或交换
统计二进制中一的个数
BrianKernighan算法
Integer工具类
bitCount
统计一的个数
toBinaryString
转二进制字符串
highestOneBit
最高位的一
lowestOneBit
最低位的一
进制转换
十进制转二进制
二进制转十进制
任意进制转换
常用API
Integer.parseInt
Integer.toString
数学技巧
最大公约数
辗转相除法
最小公倍数
乘积除以最大公约数
快速幂
分治思想
质数判断
平方根优化
随机与概率
Random类
nextInt
洗牌算法
FisherYates
常见刷题场景
位掩码
状态压缩
子集枚举
位枚举
异或问题
找唯一数
数学规律
找周期
找不变量
易错点
位运算优先级
建议加括号
溢出问题
int越界
负数位运算
补码表示
pow精度问题
double误差
排序与比较器
mindmap
root((排序与比较器))
排序基础
排序目标
升序
降序
自定义规则
排序对象
基本类型数组
对象数组
集合
Arrays排序
基本类型
默认升序
对象排序
依赖Comparable
或传入Comparator
常用方式
Arrays.sort
二维数组排序
按某一列排序
多条件排序
Collections排序
List排序
Collections.sort
底层实现
调用Arrays.sort
适用场景
ArrayList等集合
Comparable接口
定义
类内部实现
核心方法
compareTo
规则
返回负数
返回零
返回正数
特点
固定排序规则
应用
自定义类排序
Comparator接口
定义
外部比较器
核心方法
compare
写法
匿名类
lambda表达式
特点
灵活
可多规则切换
应用
临时排序需求
Lambda排序
基本写法
简化Comparator
示例
按某字段排序
多字段排序
优点
简洁
可读性强
PriorityQueue
本质
堆结构
默认规则
小顶堆
自定义排序
Comparator
常用操作
offer
poll
peek
应用
TopK问题
贪心
多条件排序
先主条件
再次条件
链式比较
常见写法
if比较
Comparator组合
常见刷题场景
区间问题
按起点排序
贪心问题
按权重排序
TopK问题
堆或排序
字符串排序
字典序
易错点
compare返回值
不能只返回1或0
整数溢出
相减比较风险
稳定性
排序是否稳定
Comparator逻辑错误
导致顺序异常
其他高频工具
mindmap
root((其他高频工具))
Collections工具类
排序
sort
反转
reverse
打乱
shuffle
最大最小值
max
min
频率统计
frequency
填充
fill
Objects工具类
判空
isNull
nonNull
比较
equals
空安全处理
requireNonNull
Character工具类
判断类型
isDigit
isLetter
isLetterOrDigit
大小写判断
isUpperCase
isLowerCase
转换
toUpperCase
toLowerCase
BigInteger
大数运算
add
subtract
multiply
divide
应用场景
超大数计算
BigDecimal
高精度小数
add
subtract
multiply
divide
注意点
精度控制
舍入模式
时间工具
System
currentTimeMillis
nanoTime
应用
性能测试
Random工具
随机数生成
nextInt
nextDouble
应用
随机测试数据
Stream流
创建
stream
常用操作
filter
map
forEach
注意
刷题中较少用
常见刷题技巧
判空处理
防止空指针
快速初始化
Arrays.asList
简化代码
工具类方法
易错点
BigDecimal比较
不能用equals
Random范围
注意边界
Stream滥用
影响性能
MyBatis
mindmap
root((MyBatis 上))
定义与定位
本质
半自动ORM
SQL映射框架
面向接口编程
核心价值
减少JDBC样板代码
SQL可控
映射灵活
适用场景
复杂查询多
需要SQL优化
对性能可控性要求高
对比
JDBC
开发繁琐
JPA
复杂SQL不够灵活
MyBatis Plus
是增强
底层仍是MyBatis
核心架构
配置层
mybatis-config
mapper.xml
typeAliases
plugins
environments
接口层
Mapper接口
动态代理
方法与SQL绑定
执行层
SqlSession
Executor
StatementHandler
ParameterHandler
ResultSetHandler
映射层
MappedStatement
ParameterMap
ResultMap
BoundSql
核心流程
启动阶段
读取全局配置
解析Mapper XML
注册MappedStatement
创建SqlSessionFactory
调用阶段
获取SqlSession
获取Mapper代理对象
调用接口方法
定位MappedStatement
执行阶段
Executor调度
StatementHandler创建预编译对象
ParameterHandler设置参数
JDBC执行SQL
ResultSetHandler封装结果
返回阶段
对象映射
一级缓存处理
提交或回滚
关闭SqlSession
重要对象
SqlSessionFactory
工厂对象
全局唯一
线程安全
SqlSession
会话对象
非线程安全
一次数据库交互上下文
MapperProxy
JDK动态代理
拦截接口方法调用
Executor
SimpleExecutor
ReuseExecutor
BatchExecutor
MappedStatement
一条SQL的完整定义
包含参数映射结果映射
SQL映射
参数传递
单参数
多参数
Param注解
Map封装
对象参数
集合参数
List
Array
占位符
井号占位符
预编译参数
防SQL注入
最常用
美元占位符
字符串拼接
有注入风险
常用于表名排序字段
返回映射
resultType
简单直接
适合单表简单对象
resultMap
复杂映射核心
更灵活
复杂映射
字段别名
一对一
association
一对多
collection
继承映射
discriminator
动态SQL
核心标签
if
条件拼接
where
自动处理前导and或or
set
自动处理更新逗号
trim
自定义前后缀
choose
类似switch
foreach
in查询批量操作
高频场景
条件查询
动态更新
批量插入
批量删除
排序分页
易错点
空集合foreach
where前多余and
set后多余逗号
美元占位符误用
mindmap
root((MyBatis 下))
缓存机制
一级缓存
作用域SqlSession
默认开启
本质本地缓存
相同SQL可复用结果
一级缓存失效
不同SqlSession
增删改后清空
手动clearCache
二级缓存
作用域Mapper级别
需显式开启
多SqlSession共享
二级缓存问题
脏数据风险
命中条件苛刻
分布式场景不常直接用
面试点
一级缓存底层
一级和二级区别
为什么生产少用二级缓存
延迟加载
作用
按需查询关联对象
降低初次查询开销
使用场景
一对一
一对多
本质
代理对象拦截getter
访问属性时再发SQL
优点
减少无效查询
缺点
容易出现N加1问题
调试不直观
面试点
延迟加载原理
aggressiveLazyLoading
何时关闭更合适
插件机制
本质
拦截器链
基于动态代理增强
可拦截对象
Executor
StatementHandler
ParameterHandler
ResultSetHandler
常见用途
分页
SQL审计
多租户
性能监控
数据脱敏
注意点
插件顺序影响结果
过度拦截增加复杂度
Spring整合
常见组件
SqlSessionFactoryBean
MapperScannerConfigurer
MapperScan
注入方式
Mapper接口注入IOC
Spring管理代理对象
事务管理
声明式事务
SqlSession与事务同步
优势
简化配置
更好管理连接事务
MyBatis Plus
定位
MyBatis增强工具
不是替代品
常用能力
BaseMapper
条件构造器
分页插件
自动填充
逻辑删除
优势
CRUD开发快
边界
复杂SQL仍回到原生MyBatis
面试高频
执行流程
接口调用到SQL执行全链路
占位符
井号与美元区别
映射
resultType与resultMap区别
缓存
一级与二级区别
延迟加载
原理与N加1
插件
能拦截哪些对象
Executor
Simple
Reuse
Batch
Mapper代理
为什么接口无实现也能调用
事务
MyBatis事务
Spring事务整合
工程实践
Mapper设计
一个聚合一个Mapper
SQL按业务分组
XML规范
SQL片段复用
命名统一
复杂查询优先XML
性能优化
避免N加1
批量操作用Batch
只查需要字段
合理索引配合SQL
安全
优先用井号占位符
严控动态表名排序字段
可维护性
SQL与业务注释清楚
复杂resultMap拆分
参数对象化
排错
打印SQL日志
关注参数为空
检查字段别名与映射
常见误区
误以为MyBatis自动生成所有SQL
误以为懒加载一定更快
误以为二级缓存生产必开
误以为美元占位符只是另一种写法
误以为SqlSession线程安全
误以为MyBatis Plus等于MyBatis
关联知识
JDBC
Connection
PreparedStatement
ResultSet
设计模式
工厂模式
代理模式
模板方法
Spring
IOC
AOP
事务
数据库
索引
事务
锁
SQL优化
Spring
SpringMVC
mindmap
root((SpringMVC))
核心定位
Web层框架
基于Servlet
处理请求与响应
属于Spring生态
核心目标
请求分发
参数绑定
返回响应
视图解析
统一异常处理
核心组件
DispatcherServlet
前端控制器
统一接收请求
统一调度流程
HandlerMapping
查找处理器
根据请求路径匹配方法
HandlerAdapter
适配调用处理器
屏蔽不同Handler差异
Controller
编写业务入口
接收参数返回结果
ViewResolver
解析视图名
定位页面资源
View
页面渲染
输出响应
Interceptor
前后置拦截
登录校验
日志统计
ExceptionResolver
统一异常处理
请求处理流程
用户发送请求
DispatcherServlet接收
HandlerMapping找Controller方法
HandlerAdapter执行目标方法
Controller处理业务
返回结果
结果分流
返回视图名
ViewResolver解析
View渲染页面
返回数据
HttpMessageConverter转换
输出Json或Xml
响应给客户端
常用注解
Controller
返回视图
RestController
返回数据
等于Controller加ResponseBody
RequestMapping
通用映射
GetMapping
PostMapping
PutMapping
DeleteMapping
RequestParam
接收请求参数
PathVariable
接收路径参数
RequestBody
接收Json请求体
ResponseBody
返回Json数据
RequestHeader
取请求头
CookieValue
取Cookie
参数绑定
基本类型
包装类型
数组
集合
JavaBean
日期类型
Json对象
文件上传
常见来源
请求参数
路径变量
请求头
请求体
返回值处理
String
视图名
ModelAndView
模型加视图
对象
转Json
List
转Json数组
ResponseEntity
自定义状态码响应头响应体
void
直接操作response
域对象与数据传递
Model
ModelMap
Map
ModelAndView
作用域
request
session
application
视图体系
JSP
Thymeleaf
重定向
redirect
转发
forward
前后端分离
多数直接返回Json
拦截器
作用
登录校验
权限控制
日志埋点
性能统计
方法
preHandle
postHandle
afterCompletion
对比Filter
Filter属于Servlet规范
Interceptor属于SpringMVC
异常处理
ExceptionHandler
局部异常处理
ControllerAdvice
全局异常处理
HandlerExceptionResolver
底层异常解析机制
数据转换
HttpMessageConverter
Json转换
字符串转换
表单数据转换
类型转换器
Converter
Formatter
上传下载
MultipartFile
单文件上传
多文件上传
文件下载
设置响应头
输出文件流
高频面试点
DispatcherServlet作用
HandlerMapping和HandlerAdapter作用
Controller和RestController区别
RequestParam和RequestBody区别
转发和重定向区别
Filter和Interceptor区别
SpringMVC执行流程
Json返回底层是谁做转换
与SpringBoot关系
SpringBoot自动配置SpringMVC
内嵌Tomcat
默认消息转换器
默认静态资源映射
开发更省配置
注解
mindmap
root((SpringMVC 常用注解))
控制器
Controller
返回视图
RestController
返回Json
等于Controller加ResponseBody
请求映射
RequestMapping
类上做模块前缀
方法上做接口映射
GetMapping
PostMapping
PutMapping
DeleteMapping
PatchMapping
参数获取
RequestParam
接收查询参数
适合name=xx
PathVariable
接收路径参数
适合user或id这类路径值
RequestBody
接收Json请求体
RequestHeader
取请求头
CookieValue
取Cookie
ModelAttribute
表单对象绑定
返回响应
ResponseBody
返回Json
ResponseStatus
指定响应状态码
结果传递
RequestAttribute
取request域数据
SessionAttribute
取session域数据
异常处理
ExceptionHandler
当前类异常处理
ControllerAdvice
全局增强
RestControllerAdvice
全局异常加Json返回
数据绑定
InitBinder
自定义参数绑定
DateTimeFormat
时间格式转换
Valid
参数校验
Validated
分组校验
跨域与会话
CrossOrigin
允许跨域
SessionAttributes
往session存模型数据
高频组合
前后端分离
RestController
GetMapping
PostMapping
RequestBody
传统页面
Controller
RequestMapping
全局异常
RestControllerAdvice
ExceptionHandler
Spring
mindmap
root((Spring 常用注解))
组件注册
Component
通用组件
Service
业务层
Repository
持久层
Controller
控制层
Scope
singleton
prototype
request
session
Lazy
懒加载
依赖注入
Autowired
按类型注入
Qualifier
指定Bean名称
Resource
先按名称再按类型
Value
注入普通值
读取配置
配置类
Configuration
配置类
Bean
注册第三方Bean
方法名默认Bean名
ComponentScan
扫描组件
PropertySource
加载配置文件
Import
导入配置类
导入组件
ImportResource
导入xml配置
生命周期
PostConstruct
初始化后执行
PreDestroy
销毁前执行
DependsOn
指定先初始化谁
AOP相关
Aspect
切面类
Pointcut
切点
Before
前置通知
After
后置通知
AfterReturning
返回后通知
AfterThrowing
异常后通知
Around
环绕通知
EnableAspectJAutoProxy
开启AOP
事务
Transactional
开启事务
作用在类
作用在方法
EnableTransactionManagement
开启事务管理
异步与定时
EnableAsync
开启异步
Async
异步方法
EnableScheduling
开启定时任务
Scheduled
fixedRate
fixedDelay
cron
缓存
EnableCaching
开启缓存
Cacheable
查缓存
CachePut
更新缓存
CacheEvict
删除缓存
环境与配置读取
ConfigurationProperties
批量绑定配置
EnableConfigurationProperties
开启配置绑定
Profile
环境切换
Primary
默认优先Bean
常见组合
注册Bean
Component
Configuration
Bean
注入Bean
Autowired
Resource
Qualifier
配置读取
Value
ConfigurationProperties
横切增强
Aspect
Transactional
Async
Cacheable
高频记忆
Component负责注册
Autowired负责注入
Bean负责第三方对象
Configuration负责配置类
Transactional负责事务
Aspect负责切面
Value负责单个配置
ConfigurationProperties负责批量配置
SpringBoot
mindmap
root((SpringBoot 常用注解))
启动类
SpringBootApplication
启动入口
组合注解
包含SpringBootConfiguration
包含EnableAutoConfiguration
包含ComponentScan
SpringBootConfiguration
本质上是Configuration
EnableAutoConfiguration
开启自动配置
配置绑定
ConfigurationProperties
批量绑定配置
适合前缀式配置
EnableConfigurationProperties
开启配置类绑定
ConfigurationPropertiesScan
扫描配置属性类
Value
读取单个配置
PropertySource
导入额外配置文件
条件装配
ConditionalOnClass
类存在才生效
ConditionalOnMissingBean
容器里没有Bean才生效
ConditionalOnBean
有指定Bean才生效
ConditionalOnProperty
配置满足条件才生效
ConditionalOnMissingClass
类不存在才生效
ConditionalOnResource
资源存在才生效
ConditionalOnWebApplication
Web应用才生效
ConditionalOnNotWebApplication
非Web应用才生效
自动配置开发
AutoConfiguration
自定义自动配置类
AutoConfigureBefore
指定先于谁生效
AutoConfigureAfter
指定后于谁生效
ImportAutoConfiguration
导入自动配置
环境与装配
Profile
区分开发测试生产环境
Primary
多个Bean时优先注入
Lazy
懒加载
Import
导入配置类或组件
Bean
注册第三方Bean
Configuration
配置类
Web相关扩展
ServletComponentScan
扫描Servlet
扫描Filter
扫描Listener
测试常用
SpringBootTest
启动Boot测试环境
MockBean
用Mock对象替换Bean
最该记住
SpringBootApplication
EnableAutoConfiguration
ConfigurationProperties
ConfigurationPropertiesScan
EnableConfigurationProperties
ConditionalOnClass
ConditionalOnMissingBean
ConditionalOnProperty
SpringBootTest
Profile
Bean
mindmap
root((Spring Bean))
Bean是什么
Spring容器管理的对象
负责创建
负责注入
负责销毁
Bean来源
Component
组件扫描注册
Service
业务层Bean
Repository
持久层Bean
Controller
控制层Bean
Configuration加Bean
手动注册第三方对象
Bean作用域
singleton
默认单例
容器中一份
prototype
每次获取新对象
request
一次请求一个
session
一个会话一个
application
整个应用一个
Bean创建流程
扫描或解析配置
BeanDefinition注册
实例化
属性注入
初始化
放入容器
后续获取使用
依赖注入
Autowired
按类型注入
Qualifier
指定Bean名字
Resource
先按名称再按类型
Value
注入普通值
生命周期
实例化
依赖注入
Aware回调
BeanPostProcessor前置
初始化方法
PostConstruct
afterPropertiesSet
initMethod
BeanPostProcessor后置
使用
销毁方法
PreDestroy
destroy
destroyMethod
重点机制
BeanDefinition
Bean的元数据
BeanFactory
最基础容器
ApplicationContext
更高级容器
单例池
singletonObjects
三级缓存
解决循环依赖
BeanPostProcessor
扩展点核心
FactoryBean
生产Bean的Bean
常见注解
Component
Bean
Scope
Lazy
Primary
DependsOn
PostConstruct
PreDestroy
高频问题
Bean和对象区别
Bean受Spring管理
Bean和Component关系
Component是注册方式
Bean和FactoryBean区别
一个是对象
一个是生产对象的工厂
单例Bean线程安全吗
看成员变量是否共享可变
为什么默认单例
节省资源
便于统一管理
多例Bean会不会注入单例
可以
生命周期管理不同
循环依赖怎么解决
单例加三级缓存
构造器循环依赖能解决吗
不能
最该记住
Bean就是交给Spring管理的对象
默认是singleton
注册方式主要是Component和Bean
注入常用Autowired和Resource
生命周期有初始化和销毁
扩展核心是BeanPostProcessor
循环依赖核心是三级缓存
数据库
MySQL
总览
mindmap
root((MySQL 总览与体系架构))
定义与本质
关系型数据库
基于表组织数据
通过 SQL 访问
核心能力
数据存储
数据查询
并发控制
事务处理
崩溃恢复
本质定位
数据管理系统
查询与更新平台
面向 OLTP 场景
整体分层
Server 层
连接管理
建立连接
权限校验
SQL 通用能力
解析器
预处理器
优化器
执行器
通用组件
查询缓存已废弃
函数与存储过程
视图与触发器
日志管理
存储引擎层
负责数据落盘
负责索引组织
负责事务细节
常见引擎
InnoDB
默认主流
支持事务
支持行锁
支持 MVCC
MyISAM
不支持事务
表锁粒度
已非主流
核心架构认知
逻辑架构
客户端
MySQL Server
Storage Engine
文件系统
物理视角
内存
Buffer Pool
各类缓存结构
磁盘
表数据
索引数据
redo log
binlog
关键思想
分层解耦
计算与存储协作
先内存后刷盘
日志优先
SQL 执行主链路
连接阶段
客户端发起连接
身份认证
权限校验
编译阶段
解析 SQL
词法分析
语法分析
预处理
表字段检查
别名处理
优化
选择索引
决定连接顺序
生成执行计划
执行阶段
调用执行器
与存储引擎交互
读取或修改数据
返回结果
写入补充
更新 Buffer Pool
记录 redo log
提交写 binlog
核心功能模块
存储
表
行
页
表空间
查询
单表查询
多表连接
聚合排序
事务
原子性
一致性
隔离性
持久性
并发
锁机制
MVCC
恢复
redo log
undo log
binlog
复制
主从复制
读写分离
InnoDB 为什么重要
默认引擎
面试主战场
核心优势
事务可靠
行级锁
崩溃恢复
高并发友好
学习重点
索引
事务
锁
日志
MVCC
常见工程场景
Web 应用后端
用户系统
订单系统
内容系统
业务特征
高频读写
强一致需求
事务更新
常见搭配
Java
SpringBoot
MyBatis
Redis
高频面试点
MySQL 架构分几层
Server 层和引擎层区别
一条 SQL 是怎么执行的
InnoDB 和 MyISAM 区别
为什么默认使用 InnoDB
MySQL 核心组件有哪些
易错点
MySQL 不等于 InnoDB
数据库不只会存数据
还负责并发控制
还负责恢复机制
SQL 执行不只是查表
还要解析
还要优化
还要选择执行计划
事务不只靠 begin commit
底层依赖锁与日志
与后续知识点的联系
索引体系
B+树
回表
覆盖索引
事务与 MVCC
undo log
Read View
锁机制
行锁
间隙锁
临键锁
日志系统
redo log
binlog
性能优化
explain
慢 SQL
索引体系
mindmap
root((MySQL 存储引擎与 InnoDB))
存储引擎
是什么
表的存储实现
决定索引 锁 事务
插件式架构
Server 层处理 SQL
引擎层负责落盘
常见引擎
InnoDB
MyISAM
InnoDB 为什么主流
支持事务
支持行锁
支持 MVCC
支持崩溃恢复
适合高并发 OLTP
InnoDB 核心结构
逻辑结构
表空间
段
区
页
行
重点单位
页 Page
默认 16KB
磁盘管理基本单位
行 Row
数据最终存在页里
索引组织
聚簇索引
叶子节点存整行数据
一张表只有一个
二级索引
叶子节点存索引列加主键
查整行常要回表
主键设计
短
稳定
递增更优
内存与性能
Buffer Pool
缓存数据页和索引页
减少磁盘 IO
脏页
先改内存
后续异步刷盘
核心思想
读写优先走内存
日志辅助持久化
事务基础
redo log
保证持久性
支持崩溃恢复
undo log
支持回滚
支持 MVCC
锁
行锁为主
InnoDB vs MyISAM
事务
InnoDB 支持
MyISAM 不支持
锁
InnoDB 行锁
MyISAM 表锁
恢复
InnoDB 强
MyISAM 弱
使用
默认优先 InnoDB
高频面试点
什么是存储引擎
为什么默认 InnoDB
聚簇索引是什么
二级索引为什么会回表
Buffer Pool 有什么作用
redo 和 undo 分别做什么
易错点
MySQL 不等于 InnoDB
行不是直接独立落盘
聚簇索引是数据组织方式
二级索引不直接存整行
SQL执行流程
mindmap
root((MySQL SQL 执行流程))
主链路
连接器
建立连接
身份认证
权限校验
解析器
词法分析
语法分析
判断 SQL 是否合法
预处理器
检查表和列是否存在
处理别名与 * 展开
优化器
选择索引
决定多表连接顺序
生成执行计划
执行器
调用存储引擎
按执行计划取数或改数
返回结果
查询执行
select
先看能否走索引
再决定扫描方式
最后回表或直接返回
核心目标
少扫描
少回表
少排序
更新执行
insert update delete
先定位数据
再修改内存页
同时写日志
关键日志
undo log
支持回滚
redo log
保证持久性
binlog
主从复制
优化器关注点
访问方式
全表扫描
索引扫描
范围扫描
代价选择
不看语法顺序
看成本更低方案
常见影响因素
索引设计
数据分布
查询条件
执行计划 explain
核心字段
type
看访问效率
key
看用了哪个索引
rows
预估扫描行数
Extra
看是否回表 排序 临时表
重点判断
是否命中索引
是否出现 filesort
是否出现 using temporary
慢 SQL 根因
没走索引
回表过多
联合索引没用好
排序分组代价高
扫描行数过大
高频面试点
一条 SQL 是怎么执行的
解析器 预处理器 优化器 执行器分别做什么
优化器为什么会选错索引
explain 重点看哪些字段
慢 SQL 一般怎么排查
易错点
SQL 写出来的顺序
不等于真实执行顺序
建了索引
不代表一定会走
explain 好看
不代表实际一定快
查询慢
不一定只是索引问题
事务隔离级别 & MVCC
mindmap
root((MySQL 事务 隔离级别 与 MVCC))
事务本质
是什么
一组 SQL 的整体执行单元
要么都成功
要么都失败
核心目标
保证数据正确
保证并发下结果可信
ACID
原子性
undo log 支持回滚
一致性
事务最终目标
由原子性隔离性持久性共同保证
隔离性
锁
MVCC
持久性
redo log
并发问题
脏读
读到别人未提交数据
不可重复读
同一事务两次读结果不同
幻读
同一事务两次范围读行数变化
隔离级别
读未提交
可能脏读
隔离性最弱
读已提交
解决脏读
可能不可重复读
可重复读
MySQL 默认
解决不可重复读
配合临键锁抑制幻读
串行化
隔离性最强
并发性能最差
MVCC
是什么
多版本并发控制
让读写尽量不互斥
依赖
undo log
Read View
隐藏字段 trx_id roll_ptr
解决什么
快照读下减少加锁
提升并发读性能
读取方式
快照读
普通 select
读历史可见版本
当前读
select for update
update delete
读最新版本并加锁
Read View
核心作用
决定哪个版本对当前事务可见
本质判断
版本是不是已提交
版本是不是属于当前事务
版本是不是在活跃事务范围内
锁与 MVCC
分工
MVCC 处理读多写少场景
锁处理当前读和写写冲突
常见锁
行锁
间隙锁
临键锁
关键理解
MVCC 不能替代锁
当前读仍要加锁
面试主线
事务四大特性怎么实现
四种隔离级别区别
MySQL 默认隔离级别是什么
MVCC 原理是什么
Read View 是什么
快照读和当前读区别
可重复读为什么还能防大部分幻读
易错点
一致性不是单独机制
MVCC 主要提升读并发
可重复读解决的是不可重复读
幻读常和不可重复读混淆
普通 select 通常是快照读
锁机制
mindmap
root((MySQL 锁机制))
锁的作用
保证隔离性
防止并发冲突
保护当前读与写操作
锁的主线
表锁
锁整张表
粒度大
并发低
行锁
InnoDB 主流
粒度小
并发高
本质锁索引记录
行锁类型
记录锁
锁住某一条记录
间隙锁
锁住一个范围
防止插入
临键锁
记录锁加间隙锁
MySQL 默认重点
用来抑制幻读
共享与排他
共享锁 S
可读
不可改
排他锁 X
可读可改
阻塞其他写
加锁场景
当前读
select for update
select lock in share mode
update
delete
快照读
普通 select
主要靠 MVCC
通常不加锁
行锁生效条件
走索引
精准命中
锁范围更小
不走索引
可能扫描大量记录
锁范围变大
核心理解
行锁本质依赖索引
死锁
是什么
事务互相等待
谁也拿不到锁
常见原因
访问顺序不一致
交叉更新多行
解决
统一加锁顺序
小事务快提交
命中索引减少锁范围
面试主线
InnoDB 有哪些锁
行锁和表锁区别
记录锁 间隙锁 临键锁区别
为什么能防幻读
普通 select 为什么不加锁
为什么说行锁本质是锁索引
死锁怎么产生 怎么解决
易错点
行锁不等于只锁一行
不走索引时锁范围会变大
普通 select 通常不是当前读
MVCC 和锁是配合关系
日志系统
mindmap
root((MySQL 日志系统))
日志主线
redo log
保证持久性
用于崩溃恢复
undo log
支持回滚
支持 MVCC
binlog
记录逻辑操作
用于主从复制
redo log
作用
先记日志
后刷数据页
核心思想
WAL
先写日志再写磁盘
随机写转顺序写
特点
InnoDB 独有
物理日志
记录页修改
关键价值
事务提交后即使宕机
数据也能恢复
undo log
作用
事务失败可回滚
提供历史版本
特点
逻辑日志
与事务版本链相关
关键价值
原子性
MVCC
binlog
作用
记录数据库变更
主从复制依据
特点
Server 层日志
逻辑日志
所有引擎都可用
常见格式
statement
row
mixed
三大日志分工
redo log
持久性
崩溃恢复
undo log
回滚
一致性读
binlog
复制
数据恢复
提交流程
写 undo log
留回滚与版本数据
写 redo log
进入 prepare
写 binlog
记录本次事务
提交 redo log
进入 commit
两阶段提交
为什么需要
保证 redo 和 binlog 一致
核心过程
redo prepare
写 binlog
redo commit
避免问题
防止主从不一致
防止恢复后数据错乱
崩溃恢复
依赖 redo log
已提交事务可恢复
未提交事务
借助 undo log 回滚
核心理解
redo 负责重做
undo 负责撤销
高频面试点
redo log 和 binlog 区别
undo log 有什么作用
WAL 是什么
为什么需要两阶段提交
MySQL 宕机后怎么恢复
三种日志分别解决什么问题
易错点
redo log 不负责主从复制
binlog 不直接保证崩溃恢复
undo log 不等于持久化日志
两阶段提交是为了一致性
性能优化 & 表设计
mindmap
root((MySQL 性能优化 与 表设计))
优化主线
少扫描
少回表
少排序
少临时表
慢 SQL 根因
没走索引
扫描行数过多
回表次数过多
排序分组代价高
join 不合理
explain
核心字段
type
看访问方式
key
看用了哪个索引
rows
看扫描行数
Extra
看排序 临时表 回表
重点信号
using filesort
using temporary
using index
索引优化
核心方向
命中联合索引
尽量覆盖索引
减少索引失效
设计原则
高频条件放前面
区分度高放前面
不乱建索引
SQL 优化
where
先过滤再取数
order by
尽量利用索引有序性
group by
尽量减少额外排序
join
小表驱动大表
关联字段建索引
limit
深分页代价高
表设计
主键
短
稳定
递增更优
字段
能小就小
尽量非空
避免超大字段滥用
冗余设计
适度反范式
用空间换查询性能
高频问题
count
count主键
count1
count星
分页
limit 很深会慢
模糊查询
前缀匹配可走索引
%开头常失效
面试主线
慢 SQL 怎么排查
explain 重点看什么
为什么深分页慢
为什么回表会慢
联合索引怎么设计
表字段为什么不建议太大
易错点
有索引不一定快
索引多会拖慢写入
explain 好看不等于真实快
优化不只看 SQL
也看表结构和数据分布
主从复制 & 高可用 & 分库分表
mindmap
root((MySQL 主从复制 高可用 与 分库分表))
主从复制
作用
读写分离
数据备份
故障切换基础
核心流程
主库写 binlog
从库拉取 binlog
从库重放日志
三线程
主库 dump 线程
从库 IO 线程
从库 SQL 线程
主从延迟
是什么
主库已提交
从库还没跟上
常见原因
从库执行慢
大事务
锁冲突
从库压力大
影响
读到旧数据
主从数据短暂不一致
优化
拆小事务
优化 SQL
提升从库配置
关键读回主库
读写分离
思想
主库负责写
从库负责读
优点
分担读压力
提高吞吐
风险
主从延迟
一致性问题
常见策略
读主兜底
延迟敏感请求走主库
高可用
核心目标
主库故障后快速切换
保证服务连续
常见方案
主从加故障转移
MHA
Orchestrator
半同步复制
关键问题
新主选举
数据一致性
脑裂
分库分表
为什么拆
单表过大
单库压力过高
扩展性不足
拆分方式
垂直拆分
按业务拆库
按字段拆表
水平拆分
按数据范围或哈希拆
核心难点
分片键设计
跨库 join
分布式事务
分页排序聚合
分片键
设计原则
分布均匀
高频查询可命中
尽量稳定
常见选择
user_id
order_id
tenant_id
影响
决定数据路由
决定热点问题
分布式 ID
为什么需要
分表后主键不能冲突
常见方案
数据库自增段
UUID
雪花算法
重点
全局唯一
趋势递增更友好
面试主线
主从复制流程是什么
binlog 在复制里做什么
主从延迟怎么产生
读写分离有什么问题
高可用怎么做故障切换
为什么要分库分表
水平拆分和垂直拆分区别
分库分表后有哪些难点
易错点
主从复制默认不是强一致
读写分离不等于高可用
分库分表不只是性能优化
分片后很多单机 SQL 能力会变复杂
高频问题
mindmap
root((MySQL 高频问题排查 与 面试串联))
排查主线
先看现象
查询慢
写入慢
锁等待
主从延迟
再找位置
SQL 问题
索引问题
锁问题
日志刷盘
架构瓶颈
查询慢
先查 explain
是否走索引
扫描行数是否过大
是否 filesort
是否 temporary
常见根因
索引失效
回表过多
深分页
join 不合理
优化方向
补联合索引
做覆盖索引
改写 SQL
写入慢
常见根因
索引太多
大事务
批量更新过大
磁盘刷盘压力
优化方向
减少冗余索引
拆小事务
分批提交
避免热点更新
锁等待与死锁
看什么
是否当前读
是否范围更新
是否未命中索引
常见根因
锁范围过大
事务太长
加锁顺序不一致
优化方向
命中索引
统一更新顺序
快速提交
主从延迟
现象
主库已写
从库未同步
常见根因
大事务
从库执行慢
复杂 SQL 重放慢
处理方向
拆小事务
优化 SQL
关键读走主库
高并发主线
读性能
Buffer Pool 命中
索引设计合理
减少随机 IO
写性能
redo 顺序写
控制索引数量
降低锁冲突
扩展能力
读写分离
分库分表
缓存配合
面试串联
查询为什么快
索引
B+树
覆盖索引
并发为什么稳
锁
MVCC
隔离级别
宕机为什么能恢复
redo log
undo log
两阶段提交
为什么能扩展
主从复制
分库分表
高频追问
一条 SQL 怎么优化
为什么走了索引还慢
为什么可重复读还能防大部分幻读
死锁怎么产生怎么解决
主从延迟怎么处理
分库分表后难点有哪些
易错点
排查慢 SQL 不只看索引
有时瓶颈在锁和 IO
高并发问题常是组合问题
单机优化和分布式优化不是一回事
Redis
总览
mindmap
root((Redis 总览))
定义与定位
内存数据库
Key Value存储
高性能NoSQL
支持持久化
常作缓存中间件
也可作轻量消息与计数系统
核心特性
读写快
基于内存
命令执行路径短
数据结构丰富
不只是String
支持多种结构化操作
支持高并发
适合热点访问
支持原子操作
单命令天然原子性
支持过期时间
TTL
EXPIRE
支持持久化
RDB
AOF
支持高可用
主从复制
哨兵
支持分布式扩展
Cluster集群
为什么快
内存访问
少磁盘IO
单线程命令执行
避免线程切换
避免锁竞争
IO多路复用
高效处理大量连接
高效数据结构
哈希表
跳表
压缩结构
C语言实现
执行开销低
数据类型
五大基础类型
String
List
Hash
Set
ZSet
特殊类型
Bitmap
HyperLogLog
GEO
Stream
学习重点
使用场景
常用命令
底层结构
时间复杂度
核心机制
过期机制
惰性删除
定期删除
内存淘汰
LRU
LFU
random
noeviction
持久化
RDB快照
AOF追加日志
混合持久化
事务与脚本
MULTI EXEC
Lua
发布订阅
Pub Sub
Pipeline
减少网络往返
高可用与扩展
主从复制
读写分离
数据副本
Sentinel
故障发现
自动故障转移
Cluster
分片存储
槽位机制
横向扩展
常见应用场景
缓存
热点数据缓存
查询结果缓存
计数器
点赞
浏览量
库存计数
排行榜
ZSet
分布式锁
set nx ex
会话共享
session存储
消息队列
List
Stream
去重与签到
Set
Bitmap
典型缓存问题
缓存穿透
缓存击穿
缓存雪崩
热Key
大Key
双写一致性
优点
性能高
使用简单
数据结构丰富
扩展方案成熟
社区生态强
局限
基于内存
成本高
容量受限
不适合复杂查询
不适合强事务核心业务
持久化能力弱于关系型数据库
缓存与数据库存在一致性问题
与MySQL关系
MySQL
持久存储
复杂查询
强一致业务
Redis
高速访问
热点数据
临时状态
常见组合
MySQL做主存储
Redis做缓存层
面试主线
Redis是什么
Redis为什么快
Redis有哪些数据类型
Redis怎么做持久化
Redis怎么保证高可用
Redis常见缓存问题有哪些
Redis和MySQL如何配合
五大数据结构
mindmap
root((Redis 五大基础数据结构))
String
本质
字符串对象
最常用类型
可存字符串数字二进制
常用命令
set
get
mget
incr
decr
append
setnx
setex
底层
SDS
记录长度
减少重复计算长度
二进制安全
典型场景
缓存对象
计数器
分布式锁
共享标记位
面试点
为什么适合计数
为什么是二进制安全
setnx加expire为什么常一起说
List
本质
有序可重复
双端链式操作
常用命令
lpush
rpush
lpop
rpop
lrange
blpop
底层
quicklist
链表加压缩列表思想
典型场景
消息队列
最新消息列表
栈
队列
面试点
为什么适合双端操作
为什么现在底层不是单纯双向链表
和Stream做消息队列区别
Hash
本质
键值对集合
适合存对象
常用命令
hset
hget
hmget
hgetall
hincrby
hexists
底层
hashtable
listpack
小对象更省内存
典型场景
用户信息
商品属性
配置项
面试点
和String存对象区别
为什么更适合存部分字段
什么时候会从紧凑结构转成哈希表
Set
本质
无序唯一集合
自动去重
常用命令
sadd
srem
smembers
sismember
scard
sinter
sunion
sdiff
底层
hashtable
intset
整数集合时更省空间
典型场景
去重
共同关注
标签系统
抽奖候选池
面试点
为什么能去重
交并差集怎么做
intset何时升级
ZSet
本质
有序唯一集合
元素带分数score
常用命令
zadd
zrem
zrange
zrevrange
zscore
zrank
zincrby
底层
skiplist
hashtable
典型场景
排行榜
延时队列
权重排序
范围查询
面试点
为什么用跳表
为什么还要配哈希表
和Set区别
和Heap区别
横向对比
String
最简单
最通用
List
强在双端操作
Hash
强在对象字段存储
Set
强在去重与集合运算
ZSet
强在排序与范围查询
选型思路
只存一个值
String
存对象多个字段
Hash
需要先进先出或双端操作
List
需要去重
Set
需要排行榜或按分数排序
ZSet
高频易错点
String不只是字符串
List允许重复
Set无序且唯一
ZSet唯一的是元素不是score
Hash适合局部字段修改
特殊数据结构
mindmap
root((Redis 特殊数据结构))
Bitmap
本质
位数组
按bit存0和1
底层依赖String
常用命令
setbit
getbit
bitcount
bitop
核心特点
极省空间
适合大规模状态标记
支持位运算
典型场景
用户签到
在线状态
活跃统计
布尔标记集合
面试点
为什么节省内存
底层为什么属于String
和Set做签到对比
HyperLogLog
本质
基数统计
统计去重数量
不是精确去重集合
常用命令
pfadd
pfcount
pfmerge
核心特点
占用空间极小
统计值有误差
适合海量去重计数
典型场景
UV统计
独立访客数
搜索词去重计数
面试点
为什么省内存
为什么有误差
为什么不能拿出具体元素
GEO
本质
地理位置集合
存经纬度
底层依赖ZSet
常用命令
geoadd
geopos
geodist
georadius
geosearch
核心特点
支持附近的人
支持距离计算
支持范围搜索
典型场景
附近门店
附近骑手
LBS位置服务
面试点
为什么底层是ZSet
如何支持距离范围查询
和普通经纬度表查询区别
Stream
本质
消息流
可持久化消息队列
支持消费组
常用命令
xadd
xrange
xread
xgroup
xreadgroup
xack
核心特点
消息可回溯
支持多消费者
支持消费确认
比List更像正式消息队列
典型场景
异步任务
消息分发
日志流处理
面试点
和List做队列区别
消费组有什么用
为什么能避免消息丢失一部分问题
特殊结构对比
Bitmap
强在状态压缩
HyperLogLog
强在海量去重计数
GEO
强在地理位置搜索
Stream
强在消息流与消费组
选型思路
只关心某状态是否存在
Bitmap
只关心去重后的数量
HyperLogLog
只关心附近位置与距离
GEO
需要可靠消息流
Stream
高频易错点
Bitmap底层不是独立新结构
HyperLogLog不能精确去重
GEO底层本质是ZSet能力扩展
Stream比List更适合消息队列
持久化
mindmap
root((Redis 持久化))
作用
宕机后恢复数据
降低内存数据丢失风险
支撑主从复制与重启恢复
持久化方案
RDB
本质
某一时刻数据快照
触发方式
save
bgsave
save规则自动触发
优点
文件紧凑
恢复速度快
适合备份
缺点
有时间点丢数据风险
fork开销大
适用场景
容忍少量数据丢失
追求恢复速度
AOF
本质
记录写命令日志
写回策略
always
everysec
no
重写机制
bgrewriteaof
压缩冗余命令
优点
数据更完整
可读性更强
缺点
文件更大
恢复更慢
适用场景
更看重数据安全
混合持久化
本质
RDB快照加增量AOF命令
特点
兼顾恢复速度
兼顾数据完整性
RDB机制
执行流程
fork子进程
子进程生成快照文件
写入临时文件
替换旧RDB
核心点
主进程继续处理请求
借助写时复制
高频问题
为什么用bgsave
fork会带来什么开销
写时复制是什么
AOF机制
执行流程
写命令追加到AOF缓冲区
按策略刷盘
重启时重放命令恢复数据
重写流程
fork子进程
根据当前内存数据重写新AOF
合并重写期间增量命令
替换旧AOF
高频问题
AOF为什么会膨胀
重写和刷盘区别
everysec为什么常用
两者对比
数据安全
AOF更强
恢复速度
RDB更快
文件大小
RDB更小
可读性
AOF更好
性能影响
RDB适合低频快照
AOF取决于刷盘策略
恢复流程
只有RDB
加载RDB恢复
只有AOF
重放AOF恢复
同时开启
优先使用AOF
混合持久化
先加载RDB部分
再执行增量命令
选型建议
只要快速备份恢复
RDB
更关注数据少丢失
AOF everysec
线上常见
RDB加AOF
或混合持久化
高频面试点
RDB和AOF区别
bgsave原理
bgrewriteaof原理
为什么AOF更安全
为什么RDB恢复更快
AOF重写会阻塞吗
RDB和AOF如何选择
易错点
RDB不是实时持久化
AOF重写不是读取旧AOF简单压缩
AOF更安全也不是绝对不丢数据
Redis持久化不能替代数据库主存储
主从复制 & 哨兵
mindmap
root((Redis 主从复制与哨兵))
主从复制
作用
数据副本
读写分离
故障恢复基础
基本结构
Master
负责写
Slave
负责同步数据
可分担读压力
复制流程
建立连接
身份确认
全量复制
命令传播
全量复制
slave发送psync
master返回runid和offset
master执行bgsave
发送RDB给slave
再发送缓冲区增量命令
增量复制
基于复制偏移量
继续同步缺失命令
核心机制
replication id
offset偏移量
复制积压缓冲区
优点
提升读性能
提高可用性
问题
主节点压力更大
复制延迟
数据不强一致
高频点
全量复制过程
增量复制依赖什么
复制积压缓冲区作用
为什么主从有延迟
哨兵Sentinel
作用
监控主从节点
自动故障转移
通知客户端新主节点
核心功能
监控
通知
自动故障转移
配置中心
监控对象
Master
Slave
其他Sentinel
故障判断
主观下线
单个Sentinel认为节点异常
客观下线
多个Sentinel达成共识
故障转移
选出leader Sentinel
选新Master
让其他Slave复制新Master
通知客户端
新主选择依据
优先级priority
复制偏移量
run id
优点
自动切主
提高可用性
局限
不能解决数据分片
故障切换期间有短暂不可用
仍可能丢少量数据
高频点
主观下线和客观下线区别
哨兵如何选leader
新主如何选举
哨兵和Cluster区别
主从加哨兵关系
主从复制
负责数据同步
哨兵
负责监控与切换
组合意义
有副本
能自动恢复
常见问题
读写分离
主写从读
复制延迟
读从库可能读到旧数据
脑裂
网络分区导致短时双主风险
数据丢失
主节点未同步完就宕机
故障恢复
依赖哨兵自动切换
对比Cluster
主从加哨兵
解决高可用
不解决海量分片
Cluster
高可用加分片
更适合大规模集群
最该记住
主从复制负责同步数据
全量复制先传RDB再补增量命令
增量复制依赖offset和积压缓冲区
哨兵负责监控和自动故障转移
主观下线是单点判断
客观下线是多数派判断
哨兵适合高可用
Cluster适合高可用加分片
cluster集群
mindmap
root((Redis Cluster集群))
核心定位
分布式集群方案
高可用加分片
解决单机容量瓶颈
解决单机并发瓶颈
支持自动故障转移
核心目标
数据分片
横向扩展
高可用
去中心化
集群结构
Master节点
负责槽位数据
负责读写请求
Slave节点
复制对应Master
Master故障时可晋升
多主多从
一个集群多个Master
每个Master可挂多个Slave
数据分片
槽位机制
总共16384个槽
每个Master负责一部分槽
路由规则
key先算CRC16
再对16384取模
定位到具体槽
好处
分片规则固定
迁移更方便
管理比一致性哈希更直接
请求路由
客户端访问节点
节点判断槽是否归自己
如果不归自己
返回MOVED
告知新节点
槽迁移期间
可能返回ASK
客户端
需要感知集群
维护槽位与节点映射
故障转移
监控方式
节点间互相通信
Gossip协议
故障判断
主观下线
客观下线
切换流程
某个Master失联
对应Slave参与选举
晋升新Master
接管原槽位
结果
提升高可用
减少人工介入
集群通信
Gossip
传播节点状态
传播槽位信息
传播故障信息
ping pong
心跳检测
去中心化
没有单独中心节点
节点共同维护集群状态
扩缩容
扩容
新节点加入
分配槽位
槽迁移
缩容
迁出槽位
下线节点
特点
以槽为单位迁移
不必整体重分布
限制与注意点
多key操作限制
尽量落同一槽
事务限制
跨槽事务受限
Lua限制
脚本内涉及key最好同槽
批量操作限制
跨槽操作可能失败
热点问题
热key仍会压垮单节点
HashTag
作用
让多个key落同一槽
写法
大括号内内容参与槽计算
场景
多key事务
多key批量操作
关联数据放同槽
优点
支持分片
支持高可用
去中心化
可横向扩展
自动故障转移
局限
架构更复杂
客户端要支持集群
跨槽操作不方便
仍可能有数据丢失
热key问题不会自动消失
对比主从加哨兵
主从加哨兵
重点是高可用
不解决分片
Cluster
高可用加分片
更适合大规模数据
高频面试点
为什么是16384个槽
Cluster如何分片
MOVED和ASK区别
集群如何故障转移
Gossip有什么作用
Cluster和哨兵区别
为什么跨槽操作受限
HashTag有什么用
最该记住
Cluster等于分片加高可用
数据按16384个槽分布
Master负责槽
Slave负责副本和故障切换
节点间靠Gossip通信
客户端要能处理MOVED和ASK
缓存与分布式锁
mindmap
root((Redis 缓存问题与分布式锁))
缓存问题
缓存穿透
本质
请求的数据不存在
缓存和数据库都查不到
后果
请求直打数据库
数据库压力暴增
解决
缓存空值
布隆过滤器
参数校验
缓存击穿
本质
热点Key失效瞬间
大量并发同时查数据库
后果
瞬时流量压垮数据库
解决
互斥锁
逻辑过期
热点Key永不过期
缓存雪崩
本质
大量Key同一时间失效
或Redis整体故障
后果
大量请求回源数据库
服务雪崩
解决
过期时间加随机值
多级缓存
Redis高可用
限流降级
热Key
本质
某个Key访问量极高
问题
单节点压力过大
解决
本地缓存
多副本分摊
热点预热
拆分Key
大Key
本质
单个Key占用内存过大
单次操作数据量过大
问题
删除阻塞
网络传输慢
主从同步压力大
解决
拆分存储
避免一次性取全量
unlink异步删除
定期扫描治理
双写一致性
本质
数据库和缓存同时存在
更新时可能不一致
常见方案
先更新数据库再删缓存
延时双删
订阅Binlog异步删缓存
难点
并发竞争
删除失败
短暂不一致
缓存更新策略
Cache Aside
读
先查缓存
未命中查数据库
再写缓存
写
先更新数据库
再删除缓存
优点
最常用
简单实用
读写穿透
应用少见
写回
适合低一致性场景
分布式锁
作用
控制共享资源并发访问
保证同一时刻一个线程执行业务
常见场景
库存扣减
定时任务防重
幂等控制
缓存重建互斥
基础实现
set nx ex
nx表示不存在才设置
ex表示加过期时间
value
唯一标识线程或请求
正确解锁
先比对value
再删除Key
保证只能删自己的锁
推荐Lua脚本原子执行
为什么要过期时间
防止持锁线程宕机
避免死锁
分布式锁问题
锁误删
场景
锁过期后被别人拿到
原线程再去删锁
解决
value唯一标识
Lua校验后删除
锁过期
场景
业务执行时间超过TTL
解决
合理设置超时时间
续期机制
看门狗
可重入
问题
同线程重复加锁会卡住自己
解决
记录线程标识和重入次数
Redisson支持可重入
主从切换锁丢失
场景
主节点刚加锁未同步到从节点就宕机
后果
新主不知道旧锁
可能多线程同时拿锁
解决
提升一致性要求
使用RedLock思路
接受Redis锁并非绝对强一致
阻塞等待
问题
获取失败后如何等待
方案
自旋重试
sleep后重试
阻塞队列配合
Redisson
优势
封装完善
支持可重入
支持续期
支持公平锁读写锁联锁
看门狗
自动续期
防止业务未执行完锁先过期
常见对象
RLock
ReadWriteLock
MultiLock
面试主线
什么是缓存穿透
击穿和雪崩区别
热Key和大Key问题
为什么更新数据库后删缓存
分布式锁为什么用set nx ex
为什么解锁要校验value
Lua脚本解决什么问题
Redis分布式锁有哪些风险
Redisson看门狗是什么
最该记住
穿透查不到
击穿热点失效
雪崩大量失效或Redis宕机
更新策略优先更新数据库再删缓存
Redis分布式锁核心是set nx ex
解锁必须校验唯一值
Lua保证校验加删除原子性
Redis锁高性能但不是绝对强一致
删除策略与淘汰机制
mindmap
root((Redis 删除策略与内存淘汰机制))
过期机制
作用
控制缓存生命周期
释放无效内存
支撑TTL业务场景
常用命令
expire
pexpire
expireat
ttl
pttl
persist
删除策略
惰性删除
含义
访问Key时再检查是否过期
优点
CPU开销小
缺点
可能长期占内存
定期删除
含义
定时随机抽查部分过期Key
优点
平衡CPU与内存
缺点
不保证立刻删光
定时删除
理论上最及时
Redis未采用
原因
定时器太多
CPU压力大
Redis实际做法
组合策略
惰性删除
定期删除
设计思路
不追求绝对实时
追求性能与内存平衡
过期Key处理流程
Key被访问
检查是否过期
过期则删除并返回不存在
后台周期任务
随机抽取设置过期时间的Key
删除已过期Key
继续循环或停止
为什么不用只惰性删除
问题
很多过期Key一直不访问
内存会被白白占用
为什么不用只定期删除
问题
可能删不及时
访问时仍需兜底检查
内存淘汰机制
触发前提
设置了maxmemory
当前内存达到上限
目标
在内存不足时决定淘汰谁
注意
淘汰和过期不是一回事
过期是时间到了
淘汰是内存不够了
淘汰策略分类
noeviction
不淘汰
写请求直接报错
volatile系列
只从设置了过期时间的Key里淘汰
volatile random
volatile ttl
volatile lru
volatile lfu
allkeys系列
所有Key都可能被淘汰
allkeys random
allkeys lru
allkeys lfu
常见策略理解
LRU
最近最少使用
更适合时间局部性场景
LFU
最不经常使用
更适合长期热点场景
random
实现简单
效果一般
ttl
优先淘汰更快过期的Key
高频对比
LRU对比LFU
LRU看最近是否访问
LFU看访问频率高低
volatile对比allkeys
volatile只淘汰过期Key集合
allkeys全体都可能淘汰
过期删除对比淘汰
过期是Key到时间自然失效
淘汰是内存不够被迫清理
适用场景
纯缓存
常用allkeys lru
常用allkeys lfu
混合存储
常用volatile lru
常用volatile lfu
严格不允许淘汰
noeviction
常见问题
为什么Redis不保证过期Key立刻删除
为了控制CPU开销
为什么会有过期Key没删掉
定期删除是随机抽查
内存满了一定先删过期Key吗
不一定
要看是否触发访问或后台扫描
生产环境常用什么策略
allkeys lru
allkeys lfu
视业务而定
面试主线
Redis过期Key怎么删除
惰性删除和定期删除区别
为什么不用定时删除
Redis内存满了怎么办
LRU和LFU区别
volatile和allkeys区别
过期删除和内存淘汰区别
最该记住
Redis采用惰性删除加定期删除
过期删除解决无效Key
内存淘汰解决内存不足
LRU看最近访问
LFU看访问频率
纯缓存场景常考虑allkeys lru或allkeys lfu