八股文

知识梳理

Java 基础

Java 的异常有哪几种?Throwble 的子类有哪些?

((20200916194439-4h97y6o “异常”))

描述一下 Java8 哪些新特性?你是如何使用 Stream 流操作的?知道 Stream 底层原理吗?

Java8 支持如下特性:

  1. Lambda 表达式和函数式接口,@FunctionalInterface 修饰的接口只能由一个函数的接口,不包括默认方法和静态方法
  2. 接口支持默认方法和静态方法
  3. 方法引用,支持四种 类型引用:构造器引用(Class::new)、静态方法引用(Class::static_method)、类的成员方法引用(Class::method)、实例的成员方法引用(instance::method)。示例如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
class scratch {
public static void main(String[] args) {
// 构造器引用
Car car = Car.create(Car::new);
List<Car> list = Arrays.asList(car);
// 静态方法引用,入参为自己
list.forEach(Car::collide);
// 类的成员方法的引用,没有入参
list.forEach(Car::repair);
// 实例对象的成员方法的引用,入参为自己
Car car2 = Car.create(Car::new);
list.forEach(car2::follow);
}
}

class Car {
public static Car create(final Supplier<Car> supplier) {
return supplier.get();
}

public static void collide(final Car car) {
System.out.println("Collided " + car.toString());
}

public void follow(final Car another) {
System.out.println("Following the " + another.toString());
}

public void repair() {
System.out.println("Repaired " + this.toString());
}
}
  1. 支持重复注解
  2. 可以获取参数名称,需要编译增加 -parameters 参数,可以在 maven 的 compile 过程增加该参数
1
2
3
4
5
6
7
8
private static void compile() throws NoSuchMethodException {
// javac -parameters Java8Test.java
// java scratch 输出 args,不带 -parameters 参数则输出 arg0
Method method = scratch.class.getMethod( "main", String[].class );
for( final Parameter parameter: method.getParameters() ) {
System.out.println( "Parameter: " + parameter.getName() );
}
}
  1. Optional、Streams、Date/Time API、并行数组
  2. ConcurrentHashMap(((20200930172816-sf88c8v “ConcurrentHashMap 的实现原理与使用”)))、concurrentForkJoinPool、StampedLock(((20200925172739-4h7jrms “StampedLock 详解”)))、原子变量(((20200925175233-ur4xqzv “原子变量详解”)))
  3. 类依赖分析工具 jdeps
  4. Metaspace 代替 PermGen space(((20200925231449-p5eetg4 “JVM 运行机制”)))

详情参考:((20201005234154-te3yj73 “Java8 的新特性”))

HashMap 和 HashSet 的底层实现原理

  1. put 过程
  2. get 过程,其中的效率红黑树优化
  3. hash 过程
  4. resize 过程,其中的死锁问题

((20200915004102-t3x94b1 “5.1 HashMap”))

死锁及打破方式;(互斥、请求与保持、循环等待、阻塞;超时、银行家算法)

线程&协程;(blabla…)

阻塞 IO、非阻塞 IO、同步 IO、异步 IO、IO 多路复用(区别及内部流程、用户态内核态 blablabla…)

请描述一下从浏览器输入一行请求 url 开始,SpringMVC 的整个处理过程

DispatcherServlet 调用 handlermapper,根据 url 映射到 controller 处理器。最后通过参数解析,返回包装到 view。

请求是先 Filter 还是先经过 Servlet?Servlet 处理完后,还会经过 Filter 吗?

拦截器是全局生效,包括静态资源也拦截,常用于字符串编码,cros 拦截

maven 是 compile、package、install 啥区别

他们属于同一个生命周期,一共三生命周期:clean、defaul、site。其中 compile 是编译代码、package 是打成包到当前 target 目录,install 是将包上传到本地仓库

2. 并发基础

1. 公平锁和非公平锁的区别

非公平锁进来时先进行 state 的 CAS 公平锁要判断是否有线程在队列中等待

非公平锁 CAS 失败后,执行 tryAcquire 时,没有判断线程队列是否有等待,直接再进行 state 的 CAS,如果失败后,再和公平锁一样,进队列等前节点唤醒

2. Java 有哪些同步机制?说一下 volatile 关键字

ReentrantLock、Synchronized、volatile、final、wait/notify、Semaphore、Condition

同步要求保证:有序性、可见性、原子性。其中 volatile 保证了可见性和原子性。

3. Java 线程有几种状态

  1. New
  2. Runnable
  3. Blocked
  4. Waiting
  5. timed_waiting
  6. terminated

4. 说一下 sleep() 和 wait() 方法的区别

  1. Thread.sleep()不会释放占有的锁,Object.wait()会释放占有的锁
  2. Thread.sleep()必须传入时间,Object.wait()可传可不传,不传表示一直阻塞下去
  3. Thread.sleep()到时间了会自动唤醒,然后继续执行
  4. Object.wait()不带时间的,需要另一个线程使用 Object.notify()唤醒
  5. Object.wait()带时间的,假如没有被 notify,到时间了会自动唤醒,这时又分好两种情况,一是立即获取到了锁,线程自然会继续执行;二是没有立即获取锁,线程进入同步队列等待获取锁

5. 如何唤醒处于睡眠状态的线程

通过 interrupt 方式

6. 如何释放处于等待中的线程

notify

7. Executor 创建的线程池,有哪几种类型?

  1. newCachedThreadPool:0,MAX,60,SynchronousQueue
  2. newFixedThreadPool:core,core,0,LinkedBlockingQueue
  3. newScheduledThreadPool:core,MAX,0,DelayedWorkQueue
  4. newSingleThreadExecutor:1,1,0,LinkedBlockingQueue
  5. newWorkStealingPool:parallelism,asyncMode ? FIFO_QUEUE : LIFO_QUEUE

((20200919140157-d41qw7t “线程池”))

8. Executor 创建线程池的构造方法的参数都有哪些,线程池的关闭,线程池使用 interrupt 怎么样?

core, max, keepalive, timeunit, blockqueue, threadfactory, rejecthandler

9. corePoolSize = 5,maximumPoolSize = 10,那么现在有 4 个任务同时进来,这时会创建几条线程?如果还没处理完又进来 2 个任务,此时又会创建几条线程还是不会创建?

不会创建。

创建 1 个。

10. 还有哪些最原生最简单使用多线程的方法?

  1. 继承 Thread
  2. 实现 Runnable
  3. tiimer
  4. future/callable

11. blockqueue 原理,condition 和普通 wait 的区别

12. new 一个对象都经历了那几个过程?(考反射)

new:

  1. new 关键字创建一个 Java 对象时,JVM 首先会检查这个 new 指令的参数能否在常量池中定位到一个类的符号引用
  2. 然后检查与这个符号引用相对应的类是否已经成功经历加载、解析和初始化等步骤,里面会对静态变量初始化,重新赋值
  3. 类完成装载步骤之后,就已经完全确定出创建对象实例时所需的内存空间大小,接下来 JVM 将会对其进行内存分配,以存储所生成的对象实例(分配可能在栈上分配,否则在堆上使用指针碰撞或空闲列表方式创建)
  4. 调用构造方法生成一个对象

反射:

  1. class.forName()指定了 ClassLoader 后,就可以在指定的环境中查找某些类,即加载类可以在编译时不存在,运行时存在
  2. 实例

13. 锁膨胀过程和锁的优化

锁优化:自旋锁、锁粗化、锁消除、偏向锁和轻量级锁
偏向锁:

3. 消息基础

在哪里使用过消息队列?不使用消息队列可以吗?使用过哪些消息队列?有哪些优劣势?(顺序性如何保证?事务消息如何保证?消息重复了怎么办?消息丢失了怎么办-> 消息队列的常见解决方案:)消息队列引入之后的缺点?MQ 挂了怎么办?

参考:

  1. MQ 的设计概要:https://zhuanlan.zhihu.com/p/21649950,这个地址搞通可以回答 80%。
  2. 还需要看其它的消息队列,进行优劣势对比。
  3. rocketmq 的 example:http://rocketmq.apache.org/docs/transaction-example/

答:短信使用过,我在钉钉开发的时候,审批通过回调需要调用短信项目来给审批人发送短信,实际调用的就是消息队列,放在消息队列中,等待短信中台去消费来实际发送短信。消息队列本身是用来解耦、异步和削峰。但是系统可用性就会降低,MQ 中间件挂掉怎么办?复杂性,重复数据和丢失数据的处理,幂等性。一致性,多个系统同时需要处理数据,如果只有某个系统失败,那么数据就会出现不一致。

回答中透露出三个点:
解耦:如果不使用,你单独 A 系统对接 B、C 系统还要分别考虑重试机制。
异步:发送多个消息,快速返回,消息系统异步的执行任务。
削峰:A 业务系统只能接受每秒 5K 条消息,但是中午达到了 1W 条每秒,可以使用 MQ,接受 1W 条消息,然后 A 业务系统以每秒 5K 条消息慢慢进行消费,虽然会有消息堆积,但是不会持续时间很长

我们用的 push 方式、使用过顺序消息、重置位点。

消息重复发送怎么办?(即幂等性)

例如 kafka 的重复消费场景

消息丢失怎么办?

现在你要设计一个广告计费,用户点击一次发送消息进行计费结算,如何保证?(涉及金额)

  1. 生产者消息发送到 MQ 过程中由于网络问题, MQ 没收到,消息丢失。这需要发送消息的时候需要回调:MQ 收到了消息。
  2. MQ 突然宕机停电,这需要开启持久化。(有可能还没持久化到磁盘就挂了)。
  3. 消费者消费到一半自己挂掉,MQ 以为消费已经被消费了。这需要消费者每次消费完之后手动发送消费成功的 ACK。
  4. 例如 kafka,消费者在写入数据到 broker 中,broker 的 leader 在同步该消息到 follower 时,自己挂掉,重新选举了 leader 就会导致之前的消息丢失。解决方案是每次只有 leader 同步到 follower 时,才会返回生产者消息发送成功!其中 kafka 的 topic 是有首领副本的概念。

消息的顺序性保证

例如 MySQL 主从同步,是通过 binlog 来实现,从数据库通过复制主数据库的 binlog 来同步,对一条记录进行增删改,对应生成了三个 binlog 有三条记录增删改,这时将 binlog 使用 MQ 发送,就需要保证顺序性。

  1. 生产者生产消息于同一个 queue/partition:将需要保证顺序的消息发送在同一个 queue 中,这样消费者消费 queue 就会按照顺序消费。在 kafka 中就是一个 partition。
  2. 消费者消费消息:消费者使用多线程消费就会出现消费顺序不一致,因此消费者需要在消费的时候使用内存队列,例如订单的生成创建发送短信等顺序业务,可以在同一个内存队列中落盘。即使用内存队列 + 多线程来即保证了多线程性能也保证了消息的顺序性。

消息的延迟和消息积压的过期恢复?

几百万消息在 MQ 中积压了几小时怎么办?
这时候先让 3 个消费者恢复正常,然后再部署 10 倍的消费者专门消费 topic 为 consu 的消费,将 3 个消费者修改逻辑,让原来的消费者中转到 consu 中进行消费落盘,这样能快速的消费也不会对落盘数据库造成影响。
几百万消息在 MQ 中积压了几个小时,由于过期失效策略导致消息没了怎么办?
晚上凌晨在消息的源头补数据重新导入到 MQ 中。(不要设置过期失效策略)
几百万消息 在 MQ 快满了怎么办?
消费者快速消费,消费完就丢掉不做处理,然后再使用方案 2。或者导入到其它的 MQ 中进行中转消费。

消息位点重置原理

事务消息原理

如何设计一个消息中间件?

  1. 支持分布式(可用性)
  2. 落盘顺序写(持久化)
  3. 消息多个副本,并使用 zk 做 leader follower
  4. 数据丢失,内部每次写都进行落盘(每秒)或者写入 MQ 就持久化
  5. 消息顺序性,使用单个线程。
  6. 消息堆积能力
  7. 两次 RPC + 消息存储。
  8. 计算存储分离
  9. 弹性扩容缩容
  10. 网络、存储、复制、高可用、刷盘、堆积、顺序、幂等、事务
  11. 元数据中心同步
  12. 生产者消费者模型设计(缓冲队列),推拉模式

消息的重复处理

  1. 依赖 Exactly-once 语义,根据消息消费表 + 事务来做状态的更新,局限在于,如果有非 MySQL 操作或跨库就有问题,而且引入了事务
  2. 插入消息消费状态表,插入失败再稍后重试。
  3. 根据消息内容做重试(messageKey)。为了解决 md5 可能重复,messageKey 为 topic+tag+md5(body)做 Redis 锁一段时间,我们是锁两天,方便重置位点和解决问题的时间
  4. 机器重启过程的消息重复几率很大,因此需要在 bean 初始化后启动 consumer,bean 销毁前关停 consumer。producer 直接在 initmethod 使用 init/destory 即可。

消息可靠性保证

数据幂等、高可用镜像集群、Confirm 机制、事务机制、持久性

搜索基础

Spring/Mybatis

Spring 如何加载注解

Spring 启动流程、bean 实例化

MyBatis 如何防止 SQL 穿透

使用 # 而不是 $,底层使用 PreparedStatement,基于 SQL 预编译的替换

Spring 的 PostProcessor 接口起到什么作用

bean 初始化后回调,包括初始化前和初始化后的回调,例如 Apollo 的 ApolloConfig 注解,就是在初始化前增加监听器

Spring 如何实现事务

  1. ACID
  2. 隔离级别:读未提交、读已提交、可重复读、串行读
  3. 传播机制:require、support、mandatory、requires_new、not_support、never、nested
  4. 事务行为:事务开启、事务提交、事务回滚
  5. 事务切面:根据 ThreadLocal 获取是否有事务

如何在 Bean 对象中获取 ApllicationContext 上下文对象?

实现 ApplicationContextAware,原理是读取配置文件(注解扫描)后调用 refresh()

refresh:调用 FactorypostProcessors,初始化事件、注册事件监听器、通知子类刷新容器、初始化单例对象。

动态代理有哪些?JDK 动态代理和 cglib 有什么不同?

  1. JDK 代理:继承 Proxy,实现目标实现类的接口,将代理的方法都加上 final 修饰。在动态生成的实现类里面去调用 InvocationHandler 的 invoke 方法。
  2. cglib:继承目标类,实现 Factory,通过回调钩子方法调用

为什么用 Spring data JPA 而不用 MyBatis,MQ 的选型、注册中心的选型、配置中心的选型、分库分表的选型、数据传输的选型(主要针对我的项目来问的)

6. RPC 框架

1. Dubbo序列化,默认的序列化,各个序列化区别

2. Dubbo泛化调用实现的网关优劣点

3. Dubbo 消费者到提供者执行涉及的模块

4. Dubbo SPI

5. Spring Cloud 的 Eureka

内部服务注册表有双缓存:ReadWrite 缓存和 ReadOnly 缓存,会存在短时间内服务上线不可见的情况

7. JVM 基础

jvm 内存结构介绍、代码调用过程中的内存流程

堆 虚拟机栈 本地方法栈 程序计数器 元空间
栈帧的入栈出栈过程,与线程绑定,操作数栈用来记录操作位点
Java 文件被跨平台的虚拟机编译为 .class 二进制文件,接着加载类信息到方法区,验证,准备阶段初始化类变量为默认值,解析初始化卸载

Java 如何分配内存,多线程呢?

分为堆栈(栈上分配),每个线程一个线程栈,里面独立的有本地变量,共同引用了来自堆的对象

JVM 的内存模型

  1. 程序计数器
  2. 虚拟机栈
  3. 虚拟机堆
  4. 本地方法栈:栈上分配和逃逸分析以及 TLAB
  5. 元空间:取代了方法区,而且改为了直接内存,其中运行时常量池是其部分

常见异常:OutOfMemoryError: GC Overhead Limit Exceeded/Java heap space/MetaSpace

方法区是接口,永久代是实现。

内存分配:指针碰撞、空闲列表。内存回收:引用计数、可达性分析

((20200925230314-cidbmyl “【11】JVM 基础入门”))

类加载机制

类的加载过程:

  1. 加载:指 JVM 读取 Class 文件,并且根据 Class 文件描述创建 java.lang.Class 对象的过程
  2. 验证:验证文件
  3. 准备:这时候进行内存分配的仅包括类变量(static),而不包括实例变量
  4. 解析:JVM 会将常量池中的符号引用替换为直接引用,也就是得到类或者字段、方法在内存中的指针或者偏移量
  5. 初始化:执行类构造器 <clinit> () 方法的过程
  6. 卸载:所有实例被回收、加载该类的 ClassLoader 被回收、Class 对象无法通过任何途径访问(包括反射)

加载类的加载器:

  1. BootstrapClassLoader(启动类加载器):最顶层的加载类,由 C++ 实现,负责加载 %JAVA_HOME%/lib 目录下的 jar 包和类或者或被 -Xbootclasspath 参数指定的路径中的所有类。
  2. ExtensionClassLoader(扩展类加载器) :主要负责加载目录 %JRE_HOME%/lib/ext 目录下的 jar 包和类,或被 java.ext.dirs 系统变量所指定的路径下的 jar 包。
  3. AppClassLoader(应用程序类加载器) :面向我们用户的加载器,负责加载当前应用 classpath 下的所有 jar 包和类。

双亲委派模型

((20200925230314-cidbmyl “【11】JVM 基础入门”))

OOM 定位、解决方式,流程

gc 算法、扫描算法(优劣)、内存分区

JVM 中如何扫描对象;(root、hotspot 算法)、cardTable)

GC 算法(复制、标记清除、标记整理、内存碎片及解决方式)

GC 异常

什么情况下类被初始化,什么情况下类不会被初始化

类被初始化:

  1. 反射

类不会被初始化:

  1. 定义对象数组

8. 缓存基础

1. 你在公司怎么用的缓存,为什么用缓存?那会出现什么问题(缓存击穿、穿透、雪崩)?

  1. 在获取钉钉 token 时,使用的缓存,2 个小时过期,缓存 1 个小时 45 分钟,不用每次都去请求钉钉的 API。
  2. 在大规模情况下,会出现数据不一致以及缓存穿透、缓存雪崩。

2. Redis 为什么这么快,它的过期和淘汰策略是什么以及手写一个 LRU 算法

IO 多路复用 + 队列 + 事件分发(单线程) + 多线程操作 + 纯内存操作

3. Redis 高并发和高可用的集群原理

  1. 高并发:一主多从架构。
  2. 高可用:主从架构 + 哨兵。

4. Redis 持久化机制、底层原理是什么,有什么优劣?

  1. RDB:还可以做冷备,通过 runid 做 slave 的备份全量复制。按时间间隔全量备份写入磁盘。
  2. AOF:后者保证数据不丢失(1 秒)。每次操作都会写入 os cache,然后每隔一段时间写入磁盘。当 AOF 大到一定程度会执行 rewrite 操作,基于当前内存数据重新构造一个 aof 文件,将旧的 aof 文件删掉。

当同时开启了 RDB 和 AOF。重启时默认使用 AOF 恢复数据。因为 AOF 比 RDB 数据更完整。

RDB 优点:

  1. 基于 fork 子进程,对于主进程影响小。
  2. 基于 RDB 恢复数据时速度更快。
  3. 而且生成的 RDB 文件可以放在分布式存储中。方便做冷热备份

RDB 缺点:

  1. 丢数据会更多
  2. fork 子进程时,当快照文件过大时,会严重影响主进程。

AOF 优点:

  1. 默认间隔 1s ,丢失数据会更少
  2. 基于 append-only 写入,写入性能高

AOF 缺点:

  1. 因为 AOF 记录指令日志。所以AOF 文件比 RDB 文件大
  2. 影响写 QPS

5. 集群中 Redis key 如何寻址,寻址算法?hash 一致性算法

寻址算法基于 hash slot 寻址。固定 16739 取余。

使用 redis cluster,而不是 replication + sentinel。redis cluster 针对海量数据+高并发+高可用场景。

redis cluster:自动将数据进行分片,每个 master 上放一部分数据。内部支持当 master 不可用时还可以继续工作。

redis cluster 不仅有 6379 端口,还有 16379 端口,用于集群间的通信。

hash 算法演进:hash->一致性hash(自动缓存迁移)+虚拟节点(解决负载均衡问题),当某个机器宕机,会影响部分机器->redis cluster的hash slot,固定有 16739 个 slot,直接基于这个 16739 取余,就算有机器宕机,还是基于 16739 取模,这样对其它机器无影响。

redis cluster 的节点通信:内部使用 gossip 协议进行通信,元数据分布式存储,好处在于每个节点都存储了元数据,缺点在于会通信同步的的延迟。

6. 缓存、数据库双写不一致问题

先修改数据库、再删除缓存失败怎么办?这个时候先删缓存、再写数据。

  1. 删缓存成功、写数据库失败。这样其它的请求过来虽然请求的数据库是旧数据,但是写入缓存之后,是一致的。
  2. 线程 1 在删缓存成功、写数据库减少过程中,线程 2 读缓存为空,读数据库为 1000,这时候就设置了缓存为 1000。线程 1 数据库减少 1,变成 999。使用内存队列,同一个商品 id、订单 id 取模进行分发操作缓存和数据库,实现原子化。
  3. 分布式,多机器下,内存队列单点热化,在 ng 层就实现负载。

7. Redis 并发写的问题,即顺序问题

解决方案在于分布式锁和数据库中的时间戳版本号,不要用旧版本号覆盖新的版本号即可。

8. 公司的 Redis 架构,多少台,多少内存,多少核,CPU,主从架构,QPS?

9. 热点 key 的缓存,以及大对象的缓存问题解决。

10. Redis pipline 是全双工还是半双工

11. jedis 是否使用连接池,如何处理有序数据

12. Redis 数据结构类型及源码简述;

(String、Hash、ZSet、Set、Dict、GEO、HyperLogLog、BloomFilter、Stream、Bitmap 等)

13. Redis 并发竞争 Key 问题

  1. 分布式锁
  2. 写入数据库的时候,需要保存一个时间戳。假设时间戳如下
    系统 A key 1 {valueA 3:00}
    系统 B key 1 {valueB 3:05}
    系统 C key 1 {valueC 3:10}
    那么,假设这会系统 B 先抢到锁,将 key1 设置为{valueB 3:05}。接下来系统 A 抢到锁,发现自己的 valueA 的时间戳早于缓存中的时间戳,那就不做 set 操作了

14. Redis Replication 全量复制过程

  1. master 执行 bgsave,本地生成 rdb 快照文件(通过配置可以设置文件是否落盘)
  2. master -> slave
  3. master 在生成 rdb 过程中,期间的命令写入内存
  4. 如果复制过程中,内存写入数据过多(可配置)那么复制失败
  5. slave 收到 rdb,清空旧数据,然后加载 rdb 到内存,并提供服务(此时是旧数据)
  6. 如果 slave 开启了 aof,那么会立即执行 bgrewriteaof,重写 aof。

slave 第一次连接 master,会执行全复制。它们都会维护自己的 offset,slave 会上报到 master。
master 维护了 backlog,大约 1M,用来解决复制过程中的断传,后面进行增量。
当 master 回滚数据时,slave 会通过 run id 和 master 不同来发去全量复制。

15. Redis sentinel 机制

类似 zk 的功能,sentinel 自身高可用集群,用来监控 master 和 slave,负责 Redis 整体集群的高可用。

16. Redis 的数据丢失和脑裂问题

问题:由于 master->slave 异步,可能会丢失
解决:min-salves-write 和 min-slaves-max-log 配置,如果 slave 复制和 ack 延迟太长,master 拒绝写请求,保证数据不会丢,此时客户端可以将数据临时写入 MQ,定时任务将 MQ 刷入 Redis
问题:由于网络分区,多个 Redsi 集群互不通信,有多个 Master 接收写入,当脑裂恢复后,其它 Master 的数据会丢失。
问题:和丢失数据解决方案相同,如果 slave 和 master ack 延迟过大,直接拒绝请求,不会导致消息丢失过多。

17. Redis 实现分布式锁的几种方式,优劣

18. Redis 分片

  1. 客户端分片
  2. 代理分片
  3. 一致性hash
  4. 虚拟节点分片

19. sentinel 的作用,以及选举 slave 为 master 过程

sentinel 三大作用:

  1. 集群监控:监控 master 和 slave 进程是否正常工作
  2. 消息通知:某个实例有问题,可以报警给管理员
  3. 故障转移:master 故障则转移到 slave 中
  1. sentinel 觉得 master 宕机,主观宕机
  2. 大多数 sentienl 觉得 master 宕机,客观宕机
  3. 选举 master 的考虑优先级:
    1. 跟 master 断开时长
    2. slave 优先级(配置文件slave priority)
    3. 复制的 offset(复制进度)
    4. run id

9. 数据库

1. MySQL 索引类型有多少种

  1. 主键索引:alter table table_name add primary key_name(column)
  2. 唯一索引:alter table table_name add unique(column)
  3. 普通索引:alter table table_name add index index_name (column )
  4. 全文索引:alter table table_name add fulltext (column)

聚簇索引:索引结构和数据一起存放,例如主键索引叶子节点就存了数据,其中 innodb 的 .ibd 文件就包含了该表的索引和数据。

非聚簇索引:索引结构和数据分开存放,例如 MYISAM 的 .MYI 文件包含了表的索引,叶子节点存储索引和索引对应数据的指针,指向 .MYD 文件的数据。

非聚集索引的叶子节点并不一定存放数据的指针, 因为二级索引的叶子节点就存放的是主键,根据主键再回表查数据。
聚簇索引缺点:依赖有序数据,更新代价大(数据被修改索引也被修改)
非聚簇索引缺点:依赖有序数据,回表查(回查 .MYD 数据文件)

其中主键索引叶子节点存 data(聚簇索引,),二级索引叶子节点存主键 key,再回查主键索引树

2. MySQL 索引的使用与优化

覆盖索引、不回表、最左前缀、索引字段选择、数据量大时,优化器可能会使用不好的索引需要使用 force index

3. MyBatis 是如何执行 SQL 语句的

SQLSessionFactory->SqlSession->Executor->StatementHandler->ParameterHandler->TypeHandler->ResultSetHandler

其中二级缓存在解析 mapper 标签时创建,接着再 CachingExecutor 里面的 TransactionalCacheManager 中保存了这个引用,也就是跨 sqlsession(同时也是跨 executor 的,因为创建 sqlsession 时 executor 也会创建新的)。

4. JDBC 获取数据库连接的大概过程(从 getConnection 开始)

  1. 导包
  2. 反射注册驱动
  3. 打开连接获取 connection
  4. 执行查询,statement
  5. 获取结果集
  6. 释放资源

5. PreparedStatement 和 Statement 区别

prepareStatement 继承自 Statement,会先初始化 SQL,先把这个 SQL 提交到数据库中进行预处理,prepareStatement 可以在 SQL 中用?替换变量;

而 Statement 直接 SQL 编译,执行一次编译一次,而且存在 SQL 注入风险

6. MyBatis 的一些 API 接口,比如 SqlSession、sessionFactory 等等

  1. 参数处理:ParameterHandler
  2. 结果集处理:ResultSetHandler
  3. statement 实例:StatementHandler(PreparedStatment/Statement/CallableStatement),例如设置超时时间返回行数
  4. 执行器:Executor,模板模式,例如 缓存,事务,连接

7. 线上为什么用 RR 级别

8. 请问是不是每次连接数据库都创建一个连接?线程池你都有哪些了解?有接触过哪些线程池?

9. 数据库联表查询时,左连接和右连接的区别

10. 说说 MySQL 的七种事务隔离级别

11. MVCC

10. APM

1. skywalking 基本架构

分布式理论

云原生是什么

一致性 Hash 算法详解

项目实战

你是通过什么方式进行学习的?

随便讲个源码组件源码结构及内部核心原理

自己技术发展方向

读过什么组件源码 Redis、JVM、MyBatis、Spring 及相关基本都读过、sharding-jdbc 等)

看什么书