集合
arraylist和linkedlist的区别?
1、数据结构不同
ArrayList是Array(动态数组)的数据结构,LinkedList是Link(链表)的数据结构
2、效率不同
当随机查询访问ArrayList时,ArrayList比LinkedList的效率更高,因为LinkedList是线性的链表数据存储方式,
所以需要移动指针(遍历链表)从前往后依次查找。
当对数据进行增加和删除的操作时,LinkedList比ArrayList的效率更高,因为ArrayList是数组,
所以在其中进行增删操作时,会对操作点之后所有数据的下标索引造成影响,需要进行数据的移动
(
**重要:**
2.1、尾插法插入数据效率并不比LinkedList低,因为只需要往数组后面添加元素即可,不涉及到数据移动,
但是如果尾插达到数组的最大长度(默认是10),ArrayList将会进行扩容,这时候就会涉及到新数组的拷贝,
效率会低。
2.2、头插法和中间随机插入时ArrayList需要进行数据的移动,所以效率会低
)
arraylist扩容原理
arraylist不给与定义数组长度的情况下,默认长度是10,当数据大于数组长度时会进行扩容。
1、扩容时创建一个新的数组,这个数组新容量等于旧容量加上旧容量右移一位
(
**重要:**不要说1.5倍了,只是第一次计算出来正好是1.5倍而已,重点记住计算公式!
新容量等于旧容量加上旧容量右移一位,例如:旧容量10>>右移一位1=5,
新容量 = 10+5;
第二次扩容15>>1=7,这里的新容量数组长度=15+7=22,以此计算)
2、然后使用Arrays.copyOf方法把老数组里面的数据拷贝到新的数组里面。
**!!!注意扩容是先创建新的数组,再把老数组的数据拷贝移动到新数组中。**
Hashmap结构和底层原理
1、结构:
jdk1.8之前是数组加链表,1.8加入了红黑树
2、原理
**2.1、什么时候链表会转换成红黑树?**
答:数组长度达到64并且链表超过8时转换成红黑树
(**重要:**必须两个条件都达到才会转换成红黑树,如果数组长度没有达到64,
hashmap会采用扩容的方式让链表数据重新分配从而减低链表长度,
所以链表是有可能长度超过8也没有转换成红黑树的情况的,
**网上大多只说链表长度超过8转换成红黑树是不准确的!还是看源码靠谱)**
2.2、扩容机制
当我们new一个hashmap时并没有初始化数组的长度,而是在我们第一次调用put方法的时候去初始化数组长度,
默认长度是16。
1、key的hash:
static final int hash(Object key) {
int h;
return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}
(这里有个二次hash计算,也就是>>>16)
**注:会问到为什么要进行二次hash?**
为了让数据分布得更加均匀,减少hash冲突!
2、判断数组是否初始化,没有则先初始化数组
3、扩容
3.1、触发扩容是当数组数据超过数组长度*负载因子0.75时就会扩容,
如果数组长度没超过64则扩容数组,如果达到64并且链表超过8则会转换成红黑树。
扩容后链表或者说数组数据会重新hash计算桶下标值,会重新分布在扩容后的数组桶下标下。
例如:数组长度16*0.75=12,那么当插入第13个数据的时候就会进行扩容,扩容两倍,16*2=32,
第二次扩容就是32*0.75=24,大于24就会进行第二次扩容,以此类推。。。
**注:为什么负载因子是0.75?**
答:因为设置大于0.75时,如果数组数据过多导致链表过长,影响查询效率
小于0.75时会导致数组频繁扩容,主要也是影响效率和数组利用率
所以0.75是比较合适的一个取值范围
**注:面试官会问你hashmap1.7和1.8的底层原理区别有哪些?**
1、以上是1.8的扩容机制,
1.7扩容并不是数组数据超过数组长度*负载因子0.75时就进行扩容,
1.7扩容是达到这个条件后还需要产生hash冲突才会扩容,
例如:我数组数据已经超过12了,但是我第13个元素的桶下标下面并没有值,
那就会直接放入对应的桶下标中,直到数组满了或者我插入的数据计算出来的桶下标下已经有元素了,
那这样才会扩容!
2、1.7是头插法,1.8是尾插法,意思就是1.7版本如果我插入了1和2两个数据,计算出是相同的桶下标,
那么先插入的值在下面,后插入的值在链表头部。
而1.8是后插入的值放在链表尾部
(**记住:7上8下**)
ConcurrentHashMap
1、ConcurrentHashMap是线程安全的,hashmap非线程安全
2、1.7主要采用分段锁(16段)+synchronized,1.8主要采用CAS(自旋)+synchronized
3、ConcurrentHashMap如果key或者value为null会抛出空指针异常,hashmap允许key或者value为null。
ConcurrentHashMap底层原理整体流程跟HashMap基本类似
**ConcurrentHashMap迭代器是强一致性还是弱一致性?HashMap呢?**
弱一致性,HashMap强一直性。
ConcurrentHashMap可以支持在迭代过程中,向map添加新元素,而HashMap则抛出了
ConcurrentModificationException,因为HashMap包含一个修改计数器,
当你调用他的next()方法来获取下一个元素时,迭代器将会用到这个计数器。
多线程
为什么要用线程池?
1、降低资源的消耗,通过重复利用已经创建的线程降低线程创建和销毁造成的消耗。
2、提高相应速度,当任务到达的时候,任务可以不需要等到线程创建就能立刻执行。
3、提高线程的可管理性,线程是稀缺资源,使用线程池可以统一的分配、调优和监控
创建多线程的几种方式?
1、继承于Thread类,重写Thread类的run()方法
2、实现Runnable接口,实现Runnable中的抽象方法:run( )
3、实现Callable接口,实现call方法
4、创建线程池的方式
(注:Thread、Runnable、Callable三种的区别和不同这里不做阐述,也需要去看一下)
怎么创建一个线程池?
线程池默认提供四种创建方式:
1.1、使用newCachedThreadPool
ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
newCachedThreadPool创建一个可缓存线程池,如果线程池长度超过处理需要,
可灵活回收空闲线程,若无可回收,则新建线程
1.2、使用newFixedThreadPool
ExecutorService fixedThreadPool = Executors.newFixedThreadPool(10);
创建一个指定工作线程数量的线程池。每当提交一个任务就创建一个工作线程,
如果工作线程数量达到线程池初始的最大数,则将提交的任务存入到池队列中
1.3、使用newSingleThreadExecutor
ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor();
创建一个单线程化的Executor,即只创建唯一的工作者线程来执行任务,来一个处理一个,
它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO,优先级)执行
1.4、使用newScheduledThreadPool
ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(5);
创建一个定长的线程池,而且支持定时的以及周期性的任务执行,支持定时及周期性任务执行
线程池的主要参数有哪些?
ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler)
线程池底层有七大参数:
corePoolSize:核心线程数
maximumPoolSize:最大线程数
keepAliveTime:过期时间
unit:过期时间的单位
workQueue:阻塞队列
threadFactory:工厂
handler:拒绝策略
线程池的工作原理?
一个线程进来会先由核心线程数进行处理,如果线程数大于核心线程数,那么其它线程首先会放到
堵塞队列等待,堵塞队列满了后才会进行扩容,创建非核心线程数,当非核心线程数达到配置的最大线程数时,
就会开启拒绝策略,当超过设置的过期时间非核心线程依然无线程可处理时,就会进行缩容,
销毁非核心线程数。
注:面试会问到的几个问题
**1、缩容的实现方式是什么机制?**
通过自旋的方式,非核心线程不断得去线程池里面拿数据处理,如果超过设置的keepAliveTime时间
还没拿到数据处理,则会销毁非核心线程,进行缩容
**2、拒绝策略有哪几种方式?**
第一种拒绝策略是 AbortPolicy(默认),这种拒绝策略在拒绝任务时,会直接抛出异常
RejectedExecutionException (属于RuntimeException)
第二种拒绝策略是 DiscardPolicy,这种拒绝策略正如它的名字所描述的一样,
当新任务被提交后直接被丢弃掉,也不会给你任何的通知。
第三种拒绝策略是 DiscardOldestPolicy,丢弃等待最久的那个线程。
第四种拒绝策略是 CallerRunsPolicy,当有新任务提交后,如果线程池没被关闭且没有能力执行,
则把这个任务交于提交任务的线程执行,也就是谁提交任务,谁就负责执行任务。
实际工作中你用那种方式的线程池?
这里一定要说自定义线程池,因为默认提供的四种线程池的堵塞队列底层容量是Integer.MAX_VALUE,
这样会导致大量线程堵塞在队列里面,有很大的风险。
所以一般去自定义线程池,重写ThreadPoolExecutor()方法!
**注:还会问你生产上核心线程数设置多少?**
核心线程数=CPU核心数+1
例如你的cpu是8核的,就设置9个核心线程数
这个值不建议说太大,这个值一定要大于cpu数,小于等于cpu的两倍,
因为小于cup数就会造成有些的cup没有利用到,
大于cpu的两倍也一样,会导致cup上下文频繁切换。
JVM
内存模型
内存模型主要包含五部分的内容:堆、栈、本地方法栈、方法区(元空间)、程序计数器。
**堆**:JVM管理的最大一块内存空间,它是所有线程所共享的一块区域。在虚拟机启动的时候创建,
该区域的唯一目的就是为了存放对象实例,几乎所有通过new创建的实例对象都会被分配在该区域。
**栈(虚拟机栈)**:也可以称为虚拟机线程栈,它是JVM中每个线程所私有的一块空间,每个线程都会有这么
一块空间。它的生命周期是与线程的生命周期是绑定的。用于存放局部变量表、操作数栈、动态连接和
方法出口等信息,每个方法从调用到完成的过程,就对应着一个栈帧在线程栈中从入栈到出栈的过程。
**本地方法栈**:本地方法栈与虚拟机栈的作用是相似,不同的是虚拟机栈为JVM执行的Java方法服务,而
本地方法栈为JVM调用的本地方法服务。
**程序计数器**:只需要占用一小块的内存空间,每个线程都会有自己独立的程序计数器,
主要功能就是记录当前线程执行到哪一行指令了,可以看作是当前线程所执行的字节码行号指示器。
**方法区(元空间)**:在JDK 8之前,方法区也称之为永久代,这部分区域与堆一样,是所有线程所共享的,
它主要用于存放被虚拟机加载的类型信息、常量、静态变量以及即时编译器编译后的代码缓存等数据。
对于一个Class文件,除了版本、字段、方法、接口等描述信息外,还有常量池表,但需要注意的是,
在JDK 7以后的版本中,字符串常量池和静态变量等被移至到了Java堆区,而到了JDK 8,抛弃了之前
永久代的概念,通过在本地内存中实现了元空间(Meta-space)来代替永久代,并把JDK 7中永久代
剩余内容(主要是类型信息)全部移至到了元空间。
所以,方法区是使用直接内存来实现,这与堆是不一样的,也就是堆和方法区用的并不是同一块物理内存
垃圾回收过程及算法
**1、常用的垃圾回收算法:**
**标记清除算法**:标记存活的对象,把未标记的回收。回收后内存不是连续的,会产生大量的不连续的碎片,
这样会导致后续创建大对象时无法分配连续的内存空间,标记对象的时候效率低。
**复制算法**:会把内存分为相同的2个部分,每次回收,会把存活的对象移动到另一边,回收当前使用的空间。
分配的内存被分成2份,实际使用空间变成正常的一半。虽然效率高而且不会出现垃圾碎片,但是需要
两块内存空间,比较耗费内存。
**标记整理算法**:在标记清除的基础上做了优化,清除完垃圾对象后会把存活的对象移动到一起,这样就
不会存在不连续的碎片,但是需要移动对象,效率低。
**2、垃圾回收过程?**
首先要了解什么样的才能算垃圾对象会被回收
1、引用计算法:每个对象要维护一个引用计数器,当这个对象被引用后该引用计数器+1,减少一个引用
后会-1,如果这个对象的引用是0,则可以认为可回收,但是很难处理循环引用的问题。
2、可达性分析:可达性分析算法是从GC Roots的对象作为起始点,从这个被称为GC Roots的对象开始
向下搜索,如果一个对象到GCRoots没有任何引用链相连时,则说明此对象不可用。也即给定一个
集合的引用作为根出发,通过引用关系遍历对象图,能被遍历到的(可到达的)对象就被判定为存活
,没有被遍历到的就自然被判定为死亡
**重要:那些可以作为GC ROOTS对象?**
1. java虚拟机栈中的引用的对象。
2.方法区中的类静态属性引用的对象。 (一般指被static修饰的对象,加载类的时候就加载到内存中。)
3.方法区中的常量引用的对象。
4.本地方法栈中的JNI(native方法)引用的对象
垃圾回收主要是年轻代和老年代
**年轻代:**采用的是复制算法,因为年轻代存活率低,垃圾回收频率最高,复制算法效率更快,
年轻代又划分三块内存区域,分别是Eden区、Form区(s0)、To区(s1),默认比例为8:1:1,
新创建的对象都会被分配到Eden区(大对象会直接进入老年代),GC时Eden区中所有存活的对象都会
被复制到“To”,而在“From”区中,仍存活的对象会根据他们的年龄值来决定去向。年龄达到一定值
(年龄阈值,可以通过-XX:MaxTenuringThreshold来设置年龄,默认是15)的对象会被移动到年老代中,
没有达到阈值的对象会被复制到“To”区域。经过这次GC后,Eden区和From区已经被清空。这个时候,
“From”和“To”会交换他们的角色,也就是新的“To”就是上次GC前的“From”,新的“From”就是上次GC前的“To”。
**不管怎样,名为To的区域是GC后永远都是空的**。
**注:这里会问到对象的年龄是存放在那里的?**
对象的回收分代年龄存放在对象头!
**扩展:Java对象的组成部分,每一个对象都由对象头、对象的实例数据区和对齐填充字节这三部分组成**。
1、对象头:
对象头由三部分组成:
Mark Word:记录对象和锁的有关信息。当一个对象被 synchronized 关键字加锁之后,
围绕锁的操作就都会和MarkWord有关联。MarkWord通常都是 32 bit位大小。
会保存一些分代年龄、无锁状态下对象的HashCode、偏向锁的线程ID、轻量级锁指向
栈中锁记录的指针、指向重量级锁的指针、锁的标志位等内容。
指向类的指针:大小也通常为32bit,它主要指向类的数据,也就是指向方法区中的位置。
数组长度:只有数组对象才有,在32位或者64位JVM中,长度都是32bit。
2、实例数据区:
该区域主要就存放着实例对象的一些字段属性内容。
3、对齐填充字节
由于JVM要求Java对象所占的内存大小应该是8bit的倍数,所以这部分主要就是将
对象大小补充为8bit的倍数,没有别的功能。
**老年代:**区域较大,对像存活率高,一般用标记整理算法
**3、jvm调优和问题排查?**
这里一般都是调整堆、栈、年轻代、老年代、垃圾回收器等。。
这里没有固定答案,要根据项目实际情况去分析,你这里可以举例遇到的jvm性能上面的错误或者瓶颈,
然后怎么去解决的。
例如:-xx:Xms和-xx:Xmx值配置一样
1、频繁垃圾回收问题:你这边可以说看日志发现有代码频繁创建大对象并且没有释放,
或者说查看jvm配置堆或者年轻代的配置太小了,然后根据项目的大小和
实际的服务器机器内存去进行了调整,网上很多说比例物理内存内存的1/8,或者说1/64的,
其实也只是一个参考和建议,主要看实际项目情况,如果我项目小对象少,我1/100也够用呢,
所以这个值自己去把握并解释一下就行。
2、OOM(内存溢出)问题:这里首先说配置了-XX:+HeapDumpOnOutOfMemoryError 和
-XX:HeapDumpPath=/Users/jarye/Downloads/heapdump.dump,这里就是配置发生内存溢出时
会在指定的目录下生成.dump的文件,然后下载这个文件用Mat工具进行查看分析原因。
3、CPU飙升居高不下问题:排查思路是先找到进程id,然后根据进程id查看线程id并进行排序,看那个线程占cpu最高,
查询到的线程id是十进制的,还需要通过printf 命令转换成十六进制,然后用jstack 命令查看线程日志。
具体操作细节大家可以网上搜一下,这里就不做明细讲解了。
jvm常见参数:
-XX:Xms 最小堆内存
-XX:Xmx 最大堆内存
-XX:Xss 栈内存
-XX:Xmn 年轻代内存
-XX:SurvivorRatio=8 设置年轻代中Eden区与一个Survivor区的比例为8:1,默认为8
-XX:NewRatio=2 设置老年代和年轻代比例大小2:1,默认为2
。。。。。。。
**4、1.8默认垃圾回收器是哪一种?**
默认是-XX:+UseParallelGC,使用的是Parallel Scavenge(年轻代)和Parallel Old(老年代)收集器组合
Spring
spring的AOP和IOC?
AOP :面向切面编程,我们将一个个的对象某些类似的方面横向抽成一个切面,对这个切面进行一些如权限控制、事物管理,记录日志等,
公用操作处理的过程就是面向切面编程的思想。AOP 底层是动态代理,动态代理又是基于反射实现的,如果是接口采用 JDK 动态代理,
如果是类采用CGLIB 方式实现动态代理。
IOC:控制反转,就是由 spring 来负责控制对象的生命周期和对象间的关系。简单来说,控制指的是当前对象对内部成员的控制权;
控制反转指的是,这种控制权不需要程序员手动去创建对象了,由其他(类,第三方容器)来创建和管理。主要是基于DI(依赖注入)
实现,方式有三种,分别是构造方法注入,setter注入,基于注解的注入(@Autowired、@Resource)
Spring boot自动装配原理和加载过程?
https://cloud.tencent.com/developer/article/2068889
Spring的对象循环依赖问题怎么解决?
https://baijiahao.baidu.com/s?id=1694034649427742142&wfr=spider&for=pc
说一下Spring的双亲委派机制?
https://blog.csdn.net/codeyanbao/article/details/82875064
Spring事务是如何实现的?那些情况会导致事务失效?
1、https://blog.csdn.net/dayuiicghaid/article/details/125262298
**注:分布式事务如何实现?**
http://www.toobug.cn/post/8390.html
这里要去了解一下mysql的binlog、redo log、undo log三个日志特性
2、https://blog.csdn.net/weixin_43564627/article/details/121354260
说一下Spring bean的作用域和生命周期?
https://blog.csdn.net/tomonkey/article/details/104801929/
以上这些都去看一下实际的讲解教学视频,跟着老师一步一步去看源码,这样才能更好理解,很多问题光背是没用的。
Java
java类加载机制?
![在这里插入图片描述](https://img-blog.csdnimg.cn/3f5e9eef714b4394bab8627c5bea97f7.png#pic_center)
类的加载过程主要分这几个阶段:加载、验证、准备、解析、初始化
1、加载:将类的.class文件中的二进制数据读入到内存中,将其放在运行时数据区的方法区内,
然后在堆区创建一个java.lang.Class对象,用来封装类在方法区内的数据结构
2、验证:验证的目的是为了确保Class文件中的字节流包含的信息符合当前虚拟机的要求,而且不会危害虚拟机自身的安全。
包括文件格式的验证、元数据验证、字节码验证、符号引用验证。
3、准备:准备阶段正式为类变量分配内存并设置类变量初始值(null或者0),这些内存都将在方法区中进行分配,
注意final修饰的static的值在这个阶段就已经完成初始化赋值了。
4、解析:解析阶段是虚拟机将常量池内的符号引用替换为直接引用的过程。
直接引用可以是直接指向目标的指针、相对偏移量或者能间接定位到目标
5、初始化:为类的静态变量赋予正确的初始值,JVM负责对类进行初始化,主要对类变量进行初始化。
JVM初始化步骤
1)、假如这个类还没有被加载和连接,则程序先加载并连接该类
2)、假如该类的直接父类还没有被初始化,则先初始化其直接父类
3)、假如类中有初始化语句,则系统依次执行这些初始化语句
反射原理?
https://blog.csdn.net/qq_35958391/article/details/124840988
MyBatis
MyBatis的一、二级缓存和底层实现运用到了什么技术?
https://dandelioncloud.cn/article/details/1481993814998056961/
重点JDBC和动态代理
**注:在分布式下开启二级缓存会有什么问题吗?**
https://www.cnblogs.com/goloving/p/14855362.html
mybatis自带的二级缓存,但是这个缓存是单服务器工作,无法实现分布式缓存
# 和 $的区别?
#是一个占位符,$是拼接符
使用# 方式引用参数的时候,Mybatis会把传入的参数当成是一个字符串,自动添加双引号。
使用$ 引用参数时,不做任何处理,直接将值拼接在sql语句中。
# 的方式引用参数,mybatis会先对sql语句进行预编译,然后再从对象里面去获取值,能够有效防止sql注入,提高安全性。
$ 的方式引用参数,sql语句不进行预编译。
MyBatis有哪些动态sql标签?
MyBatis提供了9种动态SQL标签:trim、where、set、foreach、if、choose、when、otherwise、bind;
MyBatis和MyBatis Plus的区别?
https://blog.csdn.net/m0_67391401/article/details/123778699
RabbitMQ
怎么避免消息丢失和重复消费?
避免消息丢失:https://www.cnblogs.com/frankcui/p/15374268.html
解决重复消费:https://blog.csdn.net/weixin_45393094/article/details/123150714
两条消息同时发送到MQ,消费端怎么保证按顺序消费?
https://blog.csdn.net/m0_49496327/article/details/123690279
Redis
Redis 有哪几种数据类型?分别用于什么场景?
1、String:它是二进制安全的,可以存储图片或者序列化的对象,值最大存储为512M
应用场景:共享session、分布式锁,计数器等。
2、Hash:哈希类型是指v(值)本身又是一个键值对(k-v)结构
应用场景:缓存用户信息等。
3、List:列表(list)类型是用来存储多个有序的字符串,一个列表最多可以存储2^32-1个元素。
应用场景: 消息队列,文章列表。
4、Set:集合(set)类型也是用来保存多个的字符串元素,但是不允许重复元素。
应用场景: 用户标签,生成随机数抽奖、社交需求。
5、Zset:已排序的字符串集合,同时元素不能重复.
应用场景:排行榜,社交需求(如用户点赞)。
Redis的持久化方式?
redis提供了两种持久化的方式,分别是RDB(Redis DataBase)和AOF(Append Only File)。
RDB:就是在不同的时间点,将redis存储的数据生成快照并存储到磁盘等介质上;
AOF:是将redis执行过的所有写指令通过日志方式记录下来,在下次redis重新启动时,只要把这些写指令从前到后再重复执行一遍,
就可以实现数据恢复了。
对比:RDB快照的方式在恢复数据的时候更快,但是因为是快照式的,数据完整性没有AOF高。
AOF已日志的信息记录,数据完整性高,但是日志文件过大会导致恢复数据比较慢。
RDB和AOF两种方式也可以同时使用,在这种情况下,如果redis重启的话,则会优先采用AOF方式来进行数据恢复,
这是因为AOF方式的数据恢复完整度更高。
Redis的分布式锁怎么实现?
主要是Redisson
https://www.cnblogs.com/wangyingshuo/p/14510524.html
缓存雪崩、穿透、击穿怎么处理?
https://blog.csdn.net/qq_41071876/article/details/120076924
怎么保证数据一致性?
这里可以先说可以采用先删缓存再更新数据库 或者先更新数据库再删缓存的方式,然后说明一下这两种分别产生什么问题。
1、 先删除了redis缓存,但是因为其他什么原因还没来得及写入数据库,另外一个线程就来读取,发现缓存为空,
则去数据库读取到之前的数据并写入缓存,此时缓存中为脏数据。
2、 如果先写入数据库再删缓存,如果在缓存被删除前,写入数据库后因为其他原因被中断了,没有删除掉缓存,
就也会出现数据不一致的情况。
然后再说更好的方式的话可以采用双删机制。
具体详细讲解:https://www.jb51.net/article/224160.htm
Redis的高可用有哪几种方式?
https://blog.csdn.net/weixin_44183721/article/details/126195582
**注:缓存数据倾斜问题怎么解决?**
数据倾斜就是分布不均匀的问题,这里要去了解一下redis采用的一致性hash算法
https://developer.aliyun.com/article/938465
说一下Redis的缓存淘汰策略?
https://blog.51cto.com/u_11720620/5198456
Redis内存满了怎么处理?
大key的查找没用则删除、扩容、淘汰策略这几个方面。
https://blog.csdn.net/zhizhengguan/article/details/120813836
Nginx
怎么配置反向代理和负载均衡?
https://blog.csdn.net/projectno/article/details/118303004
负载均衡有哪几种方式?
https://blog.csdn.net/Kevinnsm/article/details/114671552
Mysql
索引类型有哪几种?
https://blog.csdn.net/Ghost_hell/article/details/119822128
索引为什么快?
去了解一下B+树的数据结构再看这篇文章就很好理解了
https://blog.csdn.net/weixin_42492543/article/details/113216509
B树和B+树的区别?
https://blog.csdn.net/weixin_42112028/article/details/125483550
常见的数据库优化有哪些?
sql、索引(避免回表)、表设计、分表等方面去优化
https://blog.csdn.net/wuxianbing2012/article/details/122960591
有几种隔离级别?分别解决了什么问题?默认隔离级别是什么?
默认隔离级别:Repeatable Read可重复读(oracle是读已提交)
https://blog.csdn.net/easylife206/article/details/102814254
update一条数据是行锁还是表锁?
update时,where中的过滤条件列,如果走了索引,锁行,无法用索引,锁表。
https://blog.csdn.net/Fire_Sky_Ho/article/details/120239996
说一下Mysql的binlog、redo log、undo log分别是什么?
https://blog.csdn.net/weixin_44688973/article/details/125460075
为什么要遵循索引的最左匹配原则?
https://blog.csdn.net/qq_40277163/article/details/124131756
说一下Mysql的回表?
https://www.cnblogs.com/taojietaoge/p/16167188.html
说一下explain执行计划的一些字段意义?
https://blog.csdn.net/User_jing/article/details/119882903
Mysql和oracle的区别有哪些?
https://baijiahao.baidu.com/s?id=1706137861467720857&wfr=spider&for=pc
SpringCloud
有哪些组件?分别用处是什么?
https://zhuanlan.zhihu.com/p/150782140
这是我面试了很多公司的一个总结,在这里做个记录,大概记得这些,
后续有其他的会持续更新,有哪里写的什么不对的麻烦大家指出,我好更正,以免误人子弟