2022年5月份面试题集合

21 篇文章 2 订阅
8 篇文章 0 订阅

没回答上来或者回答的不够好的面试题集合

目录

Java

Java基础

接口和抽象类的区别?

深拷贝和浅拷贝区别了解吗?

Java集合

介绍一下HashMap?

ArrayList的扩容机制是什么样的?

HashMap和HashTable的区别?

ConcurrentHashMap 和 HashMap 的区别?

CourrentHashMap怎么实现线程安全,1.7和1.8的区别?

Java并发编程

说说 sleep() 方法和 wait() 方法区别和共同点?

sleep(0)是什么意思,有什么用?

简单聊下synchronized?

synchronized 锁升级过程?

synchronized 和ReentrantLock区别?

并发编程的三个重要特性

voliate关键字的作用

ThreadLocal 内存泄露问题

线程池执行流程?

AQS是什么?CountDownLatch是怎么实现的?

线程池数量设置多少合适?

JVM

介绍一下JVM的内存区域划分?

对象的创建过程?

垃圾回收算法?

垃圾回收器有哪些,有什么区别?

类加载器和双亲委派?

Spring

Bean的生命周期?

什么是BeanDefinition?

Bean的销毁什么时候执行、使用场景?

Spring使用三级缓存怎么解决循环依赖问题?

Spring里的BeanFactory和ApplicationContext的区别是什么?

@Bean和@Component的区别是什么?

@Autowired 和 @Resource 的区别是什么?

SpringMVC的执行流程

SpringMVC返回json格式的方式有那些?

Spring的AOP你在项目中怎么用?

@Transactional注解同类调用会怎么样?

@SpringBootAppliction这个注解由什么构成?

SpringBoot核心组件是什么?

SpringBoot自动装配原理?

SpringBoot启动流程?

MyBatis

一级缓存和二级缓存的区别和作用域?

MySQL

一条sql的执行流程?

MySQL索引有几种类型?

聊一下MySQL的存储引擎?

慢查询要怎么优化? 

mysql事务ACID和事务隔离级别?

InnoDB 有哪几类行锁?

主键和唯一索引的区别?

B树和B+树的区别?

Hash索引和B+树索引区别?

分库分表怎么做,ShardingJDBC的分片策略?

列举explain中的各个字段的参数含义?

mysql什么时候使用行锁,什么时候使用表锁?

介绍一下mysql的虚拟表?

mysql转化数据类型的函数是什么?

binlog、redolog、undolog?

Redis

redis数据结构有哪些?

redis单线程模型,为什么后期有多线程?

redis持久化策略详细说下?

redis怎么统计在线用户数量?

redis缓存穿透、缓存血崩、缓存击穿讲一下?

redis实现分布式锁的方式?

redis淘汰策略有哪些?

redis集群有几种方式?

redis哨兵模式讲一下,怎么选主?

消息队列

RabbitMQ和RocketMQ的区别?

RabbitMQ消息挤压怎么处理?

RabbitMQ高可用怎么实现,集群模式?

怎么保证消息的可靠性传输(如何处理消息丢失的问题)?

怎么保证消息的有序性?

搜索引擎

ElasticSearch的倒排索引是什么?

ElasticSearch如何防止脑裂?

分布式

讲一下分布式事务?

跨语言事务怎么实现?

nacos和eureka的区别?

CAP理论讲一下?

PAXOS算法讲一下?

系统设计

如何设计一个秒杀系统?

如何设计一个非幂等性接口?

如何设计一个数据库连接池?

项目怎么进行技术选型?

代码评审规范?

描述下责任链模式?

排查问题

CPU100%怎么排查?

锁没释放排查思路?

项目问题

各个平台(如淘宝、京东)的调用api的参数加解密算法分别有什么?

对称加密和非对称加密算法是什么?有哪些?

对账系统的T+1/T+7是什么?

项目中用到了什么设计模式?

前端问题

vue怎么向后端发起请求?

vue双向绑定是怎么实现的?

vue的生命周期?

基础问题

Linux常用命令有哪些?


Java

Java基础

接口和抽象类的区别?

共同点 :

  • 都不能被实例化
  • 都可以包含抽象方法
  • 都可以有默认实现的方法(jdk8开始接口方法可以加上default关键字定义)

区别 :

  • 一个类只能继承一个类,但可以实现多个接口
  • 接口主要是对类行为的规范约束,你实现了某个接口意味着拥有这个行为。抽象类主要用于代码复用,强调的是所属关系。
  • 接口中的成员变量默认是public static final修饰的,不能被改变且有默认值。抽象类的变量则可以在子类中被重新定义,也可以重新赋值。

深拷贝和浅拷贝区别了解吗?

  • 浅拷贝:浅拷贝会复制这个对象开辟一个新的空间,但不包括这个对象内部的属性的引用地址。
  • 深拷贝 :深拷贝会完全复制这个对象开辟一个新的空间,包括这个对象内部的属性,引用同个对象属性的地址。

Java集合

介绍一下HashMap?

HashMap是一个K-V键值对的容器,K可以存null值,但只存在一个。

jdk1.8之前的数据结构是数组+链表,当哈希冲突的时候采用的是头插法,头插法在多线程情况下有可能导致死循环,循环链的出现。

jdk1.8之后采用的是数组+链表+红黑树的实现方式,哈希冲突的时候采用的是尾插法,当链表长度大于8并且数组长度大于64的时候就会转为红黑树,不然就会先进行数组扩容(2n)。

HashSet判断两个元素相同的依据是什么?

首先判断hashCode()方法返回值是否相同,相同的话再判断equals()方法是否相同,都相同才是相同元素。

ArrayList的扩容机制是什么样的?

new ArrayList()不传参数的话jdk1.7构建容器的时候数组长度是10,jdk1.8会默认创建一个空数组,第一次add元素会扩容到10。

ArrayList扩容发生在add()方法调用的时候,会看插入元素后的长度是否大于10,小于10就不扩容,大于10就会调用grow()方法,开辟一块新空间扩容成原来长度的1.5倍,调用Arrays.CopyOf()方法把数组引用指向新的内存空间。

HashMap和HashTable的区别?


从多个维度去讨论,线程是否安全、效率、底层数据结构、扩容机制、是否支持null值添加。

线程是否安全:HashTable线程安全,HashMap线程不安全
效率:HashMap并发高、HashTable并发低
底层数据结构:HashMap使用数组+链表+红黑树实现,当hash冲突链表的阈值大于8且数组长度大于64的时候会转成红黑树,HashTable没有这样的机制。
扩容机制:HashMap默认容量是16,当扩容的时候会变成2n倍,HashTable的默认容量是11,扩容的时候会变成2n+1倍。
是否支持null值添加:HashMap可以支持key存放null,但只能有一个,value都可以存放null;HashTable的key和value都不能存放null,如果放了访问会空指针异常。

如果要使用线程安全的Map,请使用ConcurrentHashMap。

ConcurrentHashMap 和 HashMap 的区别?

底层数据结构:1.7的ConcurrentHashMap采用的是分段数组+链表的方式实现,1.8则采用跟HashMap一样的数组+链表+红黑树实现

线程安全:在1.7的ConcurrentHashMap采用的是分段锁对整个数组进行了分段,每一把锁只锁住容器的一部分数组,多线程访问的时候不同部分数据的时候就不会存在锁竞争,提高并发访问度。1.8之后采用了synchronized+cas机制,synchronized在1.6之后进行了很多优化,效率提升很大。

CourrentHashMap怎么实现线程安全,1.7和1.8的区别?

线程安全:在1.7的ConcurrentHashMap采用的是分段锁对整个数组进行了分段,每一把锁只锁住容器的一部分数组,多线程访问的时候不同部分数据的时候就不会存在锁竞争,提高并发访问度。1.8之后采用了synchronized+cas机制,synchronized在1.6之后进行了很多优化,效率提升很大。

Java并发编程

说说 sleep() 方法和 wait() 方法区别和共同点?

sleep()不会释放锁,wait()会释放锁。

两者都可以暂停线程的执行。

wait()执行后,线程不会自动苏醒,需要调用同一个对象的notify或者notifyAll,sleep()方法执行后线程会自动苏醒。

sleep(0)是什么意思,有什么用?

在线程没销毁的时候,线程有三种状态,分别是等待状态、就绪状态、运行状态。

等待状态是不会参与cpu竞争的,如果调用的是sleep(n)的话就会进入等待状态。

就绪状态会参与cpu竞争,sleep(0)的话会暂时放弃这个线程的执行,进入就绪状态的队列里,会参与cpu竞争。

顺带一提:unix系统采用的是时间片算法(一个时间片段内多个线程各占一部分时间),windows采用的是抢占算法(谁先抢到谁先执行)。

简单聊下synchronized?

synchronized关键字解决的是线程安全问题,可以修饰代码块和方法。

jdk1.6之前synchronized关键字是属于重量级锁,性能低下,底层采用操作系统的Mutex Lock指令来实现,Java的线程是映射到操作系统的原生线程之上,操作系统实现线程的切换需要有个用户态转换到内核态,这个转换时间就会比较长,有时间成本。

jdk1.6之后,synchronized进行了优化,引入了锁升级,无锁到偏向锁到轻量级锁到重量级锁的锁升级,减少锁的开销,锁的存储结构也进行了优化。

如果是代码块加上synchronized的话采用monitorenter和monitorexit的指令实现线程安全,会尝试获取对象的锁,给这个锁计数器从0变成1,monitorexit的时候把1变成0;

如果是方法加上synchronized的话,会在jvm层面加上一个flag标识(acc_synchronized)表示这是一个同步方法来实现线程安全。

synchronized 锁升级过程?

synchronized锁升级包括无锁->偏向锁->轻量级锁->重量级锁 (只可以升级,不可以降级)

Java对象的内存划分可以分为三块:对象头、实例数据、填充数据;

对象头包含两部分:一个是markword、一个是类型指针,如果是数组的话 还会存储长度;

markword里会存储这个对象自身的一些数据,如gc的次数、当前线程持有的锁,锁状态标识、hashcode之类的。

无锁:当一个对象被创建的时候,没有线程抢占资源的时候就是无锁状态;

偏向锁(一个线程):当锁处于无锁状态的时候,有一个线程访问资源获取锁的时候,会在这个对象头和栈帧中的锁记录记录当前线程id,以后只要还是该线程进入和退出同步代码块的时候,就会不需要cas来进行加锁解锁,只用简单判断一下线程id和对象头里的是否一致就行。

轻量级锁(多个线程):在偏向锁的基础上,如果有多个线程进入抢占资源,这个时候对象头的线程id不一致,就会实现cas来竞争锁,这时候就会升级成轻量级锁,会在每个线程自己的内部创建一个锁记录,将markword复制到锁记录中,然后线程使用cas将对象头的markword改成自己的线程id,如果成功就获取锁,失败就自旋

重量级锁(线程cas10次以上):当线程成功轻量级锁且有一个线程自选十次以上都没有被选上的时候,就会变成重量级锁了,线程的竞争就会让cpu进行调度。重量级锁是使用操作系统的mutex lock操作指令执行的,java的线程映射到操作系统的原生线程里面,会有一个用户态转换到内核态的过程,这个时间成本比较高,所以并发度就没之前的那么好。

synchronized 和ReentrantLock区别?

两者都是可重入锁

synchronized非公平锁,ReentrantLock默认非公平锁,可实现公平锁

synchronized是jvm层面的关键字,ReentrantLock是api层面

ReentrantLock 比 synchronized 增加了一些高级功能,如可实现公平锁,condition精准唤醒线程,等待可中断功能。

并发编程的三个重要特性

原子性、可见性、有序性

voliate关键字的作用

1、保证线程之间共享变量的可见性

2、底层根据内存屏障来实现防止指令重排序

正常new一个对象的顺序是 1.开辟一块内存空间2.初始化数据3.对象指针引用到内存空间,但指令重排序是132

ThreadLocal 内存泄露问题

通常情况下,我们创建的变量是可以被任何一个线程访问并修改的,ThreadLocal是用来让每个线程都有他们独享的变量副本。ThreadLocal底层是一个ThreadLocalMap,它的key是弱引用,value是强引用,在垃圾回收期回收对象的时候,有可能会把弱引用的对象回收掉,这时候key就会变成null值了,ThreadLocalMap底层在调用set remove方法的时候会清除掉null对象,但最好我们在使用ThreadLocal的方法结束后都手动调用一下remove方法。

如果一个对象只具有弱引用,那就类似于可有可无的生活用品。弱引用与软引用的区别在于:只具有弱引用的对象拥有更短暂的生命周期。在垃圾回收器线程扫描它 所管辖的内存区域的过程中,一旦发现了只具有弱引用的对象,不管当前内存空间足够与否,都会回收它的内存。不过,由于垃圾回收器是一个优先级很低的线程, 因此不一定会很快发现那些只具有弱引用的对象。

弱引用可以和一个引用队列(ReferenceQueue)联合使用,如果弱引用所引用的对象被垃圾回收,Java 虚拟机就会把这个弱引用加入到与之关联的引用队列中。

线程池执行流程?

  • 1、如果当前在运行的线程数不超过核心线程数,那么则创建新的核心线程去执行任务
  • 2、如果当前在运行的线程数超超过了核心线程数,那么就将任务加入到队列中去
  • 3、如果任务队列已经满了,那么就创建非核心线程去执行当前任务
  • 4、如果执行线程数超过最大线程数的时候,就会执行拒绝策略

AQS是什么?CountDownLatch是怎么实现的?

AQS是一个构建锁和同步器的一个框架,底层采用了一个虚拟的双向队列,这个队列是先进先出的,然后要等待的线程就会放进这个队列里面,底层采用了一个计数器变量,volatile int state;表示占用状态,修改这个变量是采用cas机制。

AQS 定义两种资源共享方式,一个是独占模式(只有一个线程执行),例如ReentrantLock。一个是共享模式(多个线程执行),比如CountDownLatch;

CountDownLatch当我们初始化N个线程的时候,volatile int state就是n,然后每次调用countdown()方法的时候,就会把state减1,当等于0的时候,就会unpark()主线程,然后主线程就会从await()方法阻塞的地方出来,继续执行剩余的代码;

线程池数量设置多少合适?

判断任务是CPU密集型还是IO密集型

CPU 密集型简单理解就是利用 CPU 计算能力的任务比如你在内存中对大量数据进行排序。但凡涉及到网络读取,文件读取这类都是 IO 密集型,这类任务的特点是 CPU 计算耗费时间相比于等待 IO 操作完成的时间来说很少,大部分时间都花在了等待 IO 操作完成上。

N=CPU核心数

CPU密集型任务(大量的排序 计算等等)选择N+1的数量,原因是防止线程切换浪费时间,让CPU一直运行。

IO密集型任务(网络调用,文件读取等)选择2N的数量,原因是让线程处理IO的时间,让给其他线程执行任务。

线程池七大核心参数

1、核心线程数

2、最大线程数

3、(最大线程数-核心线程数)救急线程存活时间

4、存活时间单位

5、线程池工厂

6、队列

7、拒绝策略:1、CallerRunsPolicy 由调用者执行任务 2、拒绝任务并抛异常 3、拒绝任务 4、丢弃掉最早排队的任务。

JVM

介绍一下JVM的内存区域划分?

线程共享

堆:大部分对象和数组存放的内存空间,除了部分jit即时编译器进行逃逸分析后的部分对象会放在栈上。堆分为新生代和老年代,新生代又分为eden区和幸存者0区和1区,刚创建的对象除了大对象之外会放进eden区,然后经过一次gc存活后,会进入到幸存者0区或者1区,在经过默认gc15次后会进入老年代。

方法区:存放类信息、常量、静态变量、jit即时编译器编译后的缓存热点代码等等

线程私有

程序计数器:计算当前线程执行到哪一步

虚拟机栈:局部变量、返回值之类的

本地方法栈:native方法,c++之类的。

对象的创建过程?

类加载检查->虚拟机开辟空间分配内存->初始化零值->设置对象头->调用init方法

垃圾回收算法?

1、标记清除

2、标记复制,分成两个区域,复制到另外一个内存区域,清空之前的内存区域。

3、标记整理,清除后整理内存碎片

jvm采用分代收集算法

新生代用标记复制,因为对象小,死亡的多,所以可以用复制。

老年代用清除或者整理,因为对象大,存活几率高。

垃圾回收器有哪些,有什么区别?

1、Serial

2、ParNew ,Serial多线程版本

3、CMS,并发收集,低延迟,stw时间短

4、G1,G1担任了新生代和老年代两个区域的垃圾回收,有一个可预测的停顿时间模型,并发收集,低延迟,stw时间短,底层维护了一个优先队列,会优先对优先级高的对象进行回收。

类加载器和双亲委派?

有三种类加载器和一种自定义加载器(BootStrap、Extension、App、Custom)

双亲委派

自上而下的尝试加载类,自下而上的判断类是否被加载。

Spring

Bean的生命周期?

1、从BeanDefinition里获得Bean的元数据;

2、通过反射创建出对象;

3、如果Bean有属性,调用set()方法设置属性数据;

4、如果Bean实现了各种*.Aware接口,就会调用对应的方法;

5、如果有和这个Bean相关的BeanPostProcessor对象,调用对应前置处理方法;

6、如果Bean实现了InitializingBean接口,调用对应的afterPropertiesSet()方法;

7、调用Bean的init-method方法

8、如果有和这个Bean相关的BeanPostProcessor对象,调用对应后置处理方法;

9、如果Bean实现了DisposableBean接口,调用对应的 destroy()方法;

10、如果Bean配置了destroy-method方法,或者注解标识了销毁的方法就会调用对应方法;

什么是BeanDefinition?

存放Bean的元数据信息;

例如:Bean的类名、作用域、依赖关系、生命周期、init方法、destroy方法等等;

Bean的销毁什么时候执行、使用场景?

根据生命周期的不同,销毁执行的时间也不同;

常见的生命周期有单例、多例、会话、请求

如果是单例的话,Bean的销毁会跟着Spring容器的销毁而销毁;

如果是多例的话,根据jvm的可达性分析标志为垃圾对象的时候,根据gc回收销毁;

如果是会话的话,当会话结束的时候销毁;

如果是请求的话,当请求结束的时候销毁;

销毁方法使用场景:回调/钩子函数,或者释放资源,打印日志等等;

Spring使用三级缓存怎么解决循环依赖问题?

循环依赖就是多个Bean之间依赖形成闭环,A->B,B->C,C->A。

三级缓存是指三个map

第一级缓存:singletonObjects,单例池,存放已经创建完成的Bean

第二级缓存:earlySingletonObjects,存放早期暴露出来的对象,Bean的生命周期还没结束(属性填充未完毕)

第三级缓存:SingletonFactories,存放可以创建成Bean的工厂。

解决流程:

1.A创建的过程中发现需要创建B,于是它把A放进三级缓存中,再去创建B

2.B实例化的过程中发现需要创建A,于是去一级缓存中找,没找到,去二级缓存查,还是没有,查三级缓存发现有了,于是把A从三级缓存放进了二级缓存。

3.B初始化成功后,把B放进一级缓存,这时候要回去创建A,此时B已经创建成功,直接从一级缓存中拿B来注入到A里,A这时候也创建完成,于是A进入了一级缓存。

Spring为什么使用三级缓存解决循环依赖,不用二级缓存?

其实使用二级缓存就可以解决循环依赖,使用三级缓存不是处于IOC的考虑,而是出于AOP的考虑,如果在使用二级缓存的情况下,此时在AOP的情况下,注入到其他bean的属性的对象,不是代理对象,而是原始对象。

Spring里的BeanFactory和ApplicationContext的区别是什么?

BeanFactory:是Spring最底层的接口,提供了基础的容器工厂的功能,实例化对象和拿对象的功能。

ApplicationContext:ApplicationContext是BeanFactory的子类,拥有更强大的功能,比如国际化、ResourceLoader、AOP、事件通知机制等等;

两者的区别:

1、BeanFactory不会在容器启动的时候就实例化Bean,是属于延迟加载;ApplicationContext是容器启动的时候就初始化所有的Bean,除非我们显式的开启Lazy。

@Bean和@Component的区别是什么?

@Component用于类,@Bean用于方法;

@Component搭配@ComponentScan使用,@Bean搭配@Configuration使用;

当要把第三方组件注入到自己的IOC容器的时候,不能修改源码的情况下,只能使用@Bean;

@Autowired 和 @Resource 的区别是什么?

@Autowired是Spring的,@Resource是Jdk自带的;

@Autowired默认根据类型匹配,@Resource默认根据名称匹配;

当由多个实现类的时候,都用名称匹配;

SpringMVC的执行流程

1、请求转发到DispatchServlet

2、DispatchServlet转发到HandlerMapping找到对应Handler

3、由HandlerAdapter处理Handler,返回ModelAndView

4、由ViewResolver解析ModelAndView,返回给DispatchServlet

5、DispatchServlet将响应数据返回给前端

SpringMVC返回json格式的方式有那些?

@ResponseBody;

使用各种第三方json转化工具序列化后用HttpServletResponse的输出流输出;

配置bean.xml的json视图;

Spring的AOP你在项目中怎么用?

事务@Transactional

全局异常处理器@ControllerAdvice和@ExceptionHandler

缓存处理SpringCache的对应注解@Cacheable

自定义注解实现防幂等性操作,首先定义出一个注解,还有一个AOP类用@Aspect来表明这是一个切面类,然后用@Pointcut表明当遇到Controller这些类的时候并且使用到这个注解的时候就调用这个方法。这个方法的实现就是用ThreadLocal,把当前单号放进去,然后就表明这个单号现在已经有调用在处理了,然后AOP类还加了一个方法,上面的注解是@After,在调用这个类结束后调用这个方法,这个方法就是释放ThreadLocal里的变量。

@Transactional注解同类调用会怎么样?

如果同个类一个没事务的方法调用一个有事务的方法,事务会失效;

解决方案:写在两个不同的类上,或者用AspectJ 代替 SpringAop代理,AspectJ是编译期增强,SpringAop是运行期增强;

@SpringBootAppliction这个注解由什么构成?

@ComponentScan:类扫描,扫描当前包下的所有Bean组件;

@EnableAutoConfiguration:开启自动配置;

@Configuration:标识自己是一个配置类;

SpringBoot核心组件是什么?

1、starter

2、autoconfigure

3、SpringBootCLI

4、SpringBootActuator

SpringBoot自动装配原理?

SpringBoot通过@EnableAutoConfiguration这个注解里的AutoConfigurationImportSelector类,实现的方法里,SpringFactoryLoader加载META-INFO/spring.factories文件中的自动配置类实现,自动配置类其实就是通过各种@ConditionOnXXX按需加载的配置类,想要其生效必须引入spring-boot-starter-xxx包实现起步依赖。

SpringBoot启动流程?

1、main函数找到run方法,在run方法执行之前创建SpringApplication对象,构造器创建一些默认值;

2、run方法里,首先会创建SpringBoot的应用监听器;

3、然后会加载SpringBoot的配置环境对象,一般是servlet环境,加入到应用监听器监听;

4、然后加载应用上下文,作为run方法的返回对象;

5、最后加载Spring容器,调用refreshContext方法,完成starter的自动化配置、Bean的实例化、Tomcat servlet容器的创建等等;

MyBatis

一级缓存和二级缓存的区别和作用域?

mybatis的一级二级缓存用来存放同一个查询条件的结果集;

mybatis默认缓存是一级;

一级缓存作用域在sqlsession,一次会话里;

二级缓存作用域在application,整个应用阶段,二级缓存开启的情况下,一级缓存被关闭或者提交,二级缓存才会跟着更新;

一般我们不会开启二级缓存,分布式环境下容易出现问题,一级缓存适情况而定;

MySQL

一条sql的执行流程?

一条sql一进来先经过连接器校验权限;

有缓存就命中缓存(mysql8.0移除);

sql经过语法分析器分析语法;

sql经过优化器命中索引;

sql经过执行器执行存储引擎的读写接口返回结果集;

MySQL索引有几种类型?

可以回答:主键索引、唯一索引、普通索引、联合索引、全文索引

聊一下MySQL的存储引擎?

存储引擎是一个接口规范,MySQL的存储引擎是可插拔式架构设计,MySQL的存储引擎是基于表,不是库的级别。像MyISAM在5.5版本之前是默认存储引擎,5.5版本之后是innodb,innodb以前也是第三方开发的,只是过于优秀,后期被Oracle收购了。

MyISAM和INNODB的区别有很多,比如

innodb:支持事务和外键、默认支持行锁、支持数据崩溃恢复(利用redolog),支持MVCC,索引B+树,其数据文件本身就是索引文件。

MyISAM:不支持事务和外键、只支持表锁,不支持数据崩溃恢复,不支持MVCC,索引也是B+树,但是索引文件和数据文件是分离的。

慢查询要怎么优化? 

慢查询sql的定义是由我们在MySQL的一个参数long_query_time来设置的,当我们设置成10s,10s就是慢查询,设置成1s,1s就是慢查询。然后我们要在配置文件上开启慢查询开关,mysql才会记录慢查询日志。

一般慢查询日志很多很大,我们会用一个命令 mysqldumpslow 来分析log日志,比如找出最大的几条慢查询sql这样。

慢查询优化:

1、不使用子查询

在mysql5.5之前,子查询会先查外表,再匹配内表,如果外表数据量很大,查询速度就会很慢;

在mysql5.6之后,子查询会在内部优化成join,但也只是对select预计有效,update、delete子查询就无效,所以不建议使用子查询;

2、使用in代替or

or索引会走多次,in就走一次

3、like 双百分号无法使用到索引,应该优化成右百分号

4、避免数据类型不一致,比如int类型用String来匹配

5、分组统计时可以禁止排序,默认会排序,可以加上关键字 order by null

6、减少left join,基础数据用缓存存放一个宽表;

7、去除不必要的order by语句

8、查询的时候先查id,再根据id去查询

9、使用explain关键字去分析语句是否用到了索引

慢查询优化主要有以下几点:

1、sql语句优化,去除多余的非必要语句;

2、索引优化,让所有sql尽可能走索引

3、如果是表的瓶颈,分表,单表数据量维持在1000w以内

4、如果是库瓶颈,可分库,读写分离

5、如果是物理机器性能问题,可分多个数据库节点,搭建集群;

mysql事务ACID和事务隔离级别?

ACID:原子性、一致性、隔离性、持久性。

隔离级别脏读不可重复读幻读
READ-UNCOMMITTED(读未提交)
READ-COMMITTED(读已提交)×
REPEATABLE-READ(可重复读)××
SERIALIZABLE(可串行化)×××

mysql的innodb默认是可重复读。MySQL的事务隔离级别是基于锁和MVCC机制共同实现的;

InnoDB 有哪几类行锁?

MySQL InnoDB 支持三种行锁定方式:

  • 记录锁(Record Lock) :也被称为记录锁,属于单个行记录上的锁。
  • 间隙锁(Gap Lock) :锁定一个范围,不包括记录本身。
  • 临键锁(Next-key Lock) :Record Lock+Gap Lock,锁定一个范围,包含记录本身。记录锁只能锁住已经存在的记录,为了避免插入新记录,需要依赖间隙锁。

InnoDB 的默认隔离级别 REPEATABLE-READ(可重读)是可以解决幻读问题发生的,主要有下面两种情况:

  • 快照读 :由 MVCC 机制来保证不出现幻读。
  • 当前读 : 使用 Next-Key Lock 进行加锁来保证不出现幻读

主键和唯一索引的区别?

主键:主键是一种约束,主键包含唯一索引,主键不允许空值,支持外键,一个表只能创建一个主键。

唯一索引:唯一索引是一种索引类型,唯一索引允许空值,不支持外键,一个表可以创建多个唯一索引。

B树和B+树的区别?

B数的每个节点存放索引和数据,不支持范围查询;

B+树的中间节点不存放数据,只存放索引,数据放在叶子节点,数据叶子节点顺序存放,然后叶子节点之间有指针引用。

所以B+树支持范围查询。

Hash索引和B+树索引区别?

B+树是一个平衡多叉树,中间节点存放索引,叶子节点存放数据,叶子节点之间顺序存放,用指针引用,支持范围查询,对于每个数据IO次数都一样,但是每次新增数据都要重建索引树,所以有可能有索引碎片和页分裂等情况。

Hash索引是基于hash算法实现的哈希表,优点就是自带索引,等值查询优势很大,但是不支持范围查询、不支持排序等。

所以一般我们mysql都是设置成B+树索引。

分库分表怎么做,ShardingJDBC的分片策略?

列举explain中的各个字段的参数含义?

explain可以分析sql内部执行顺序,索引是否使用,表执行顺序等;

id:sql执行顺序,id越大,优先级越大

select_type:这条sql的类型,如simple\subquery

table:这条sql用到了哪张表

type(重要):命中索引的级别,const\range\index\all等等。sql优化至少要优化到range级别,最好是ref级别。

possible_keys:可能用到的索引

key:实际用到的索引

key_len:索引字节长度,越长越好

extra:可以查出是否使用了文件排序,临时表排序,where条件,是否用到了索引。

如果查出用到了文件排序,可能是order by的字段没有加上索引,所以才会文件排序或者临时表排序。

mysql什么时候使用行锁,什么时候使用表锁?

表级锁是mysql中锁定粒度最大的一种锁,表示对当前操作的整张表进行加锁,它实现简单。最长使用的存储引擎MYISAM和InnoDB都支持表锁。

特点:开销小,加锁快;不会出现死锁;锁定力度大,发现锁冲突的概率最高,并发度最低。

行级锁是mysql中锁定力度最小的一种锁,表示只针对当前操作的行进行加锁。行锁能大大较小数据库操作的冲突,其加锁粒度最小,并发度也最高。

特点:开销大,加锁慢;会出现死锁;锁定粒度最小;发生锁冲突的概率最小;并发度也最高;

使用:MYISAM只支持表锁,不支持行锁,Innodb的话默认行锁。

扩展:全局锁用来实现主从备份的时候用到,全局锁才是最大的粒度,使用偏少

介绍一下mysql的虚拟表?

mysql的表都是存在物理磁盘里的,那种叫实表,与之相反,存在内存里,没有落盘的数据叫虚拟表,只有逻辑上存在的表。

常见的虚拟表有:

子查询;

视图;

临时表:用来导入一些数据做操作之类的,临时表只在当前MySQL连接可见,当关闭连接时,MySQL会自动删除表并释放所有空间,当临时表过大、mysql会自动落盘磁盘保存;

内存表:表结构建在磁盘上,数据在内存里,当停止服务后,表中的数据会丢失,而表的结构不会丢失。内存表也可以被看作是临时表的一种。

mysql转化数据类型的函数是什么?

cast()函数,语法为cast(field as dataType)

convert()函数,语法为convert(field,dataType)

binlog、redolog、undolog?

MySQL的Innodb存储引擎使用redolog保证事务的持久性,使用undolog保证事务的回滚、原子性。

MySQL通过binlog保证主从、数据备份恢复的数据一致性。

Redis

redis数据结构有哪些?

K-V键值对存储。

Value的类型有:String(SDS简单动态字符串)、Hash、set、zset、list(双向链表)、bitmap、布隆过滤器、geo、hyperloglog

redis单线程模型,为什么后期有多线程?

redis基于reactor模式实现单线程模型,netty也是这样实现的。核心是文件事件处理器 file event handler。

使用IO多路复用,不用每个IO请求都创建一个线程执行,防止线程上下文切换浪费时间。

后期的多线程只是为了大的对象的键值对操作,这时候会用异步创建多线程来操作指令,但核心操作还是单线程。多线程6.0后增加,需要配置文件手动开启并且设定线程数量。

redis持久化策略详细说下?

redis使用AOF和RDB来实现持久化。

RDB的意思是快照副本,redis默认持久化方式,定时快照。

AOF是追加日志,首先把记录存放在内存缓存中,根据追加策略把每个操作记录在日志里,恢复的时候顺序执行。AOF可以进行重写,比如两次set同个key的日志可以合并成最后一个set的值。

redis4.0之后开始支持AOF+RDB的混合持久化策略,把这个策略开启的话,它就会AOF重写的时候,先执行快照,再执行快照之后的AOF日志操作。

redis怎么统计在线用户数量?

使用bitmap,bitmap还可以做用户签到、活跃用户情况等场景

redis缓存穿透、缓存血崩、缓存击穿讲一下?

缓存穿透:查询缓存里没有,DB里有的数据,导致大量请求进入DB查询,解决方案:布隆过滤器。

缓存血崩:大量key同时过期,进入到DB查询。比如秒杀的时候都设了同个过期时间。解决方案:随机时间

缓存击穿:缓存过期那一刻,大量请求进来,查询DB。解决方案:加锁

redis实现分布式锁的方式?

redisson,底层使用redis+lua脚本实现,我们还可以使用setnx指令,实现原子性的操作

redis淘汰策略有哪些?

过期数据的淘汰策略我们可以分为两种:惰性删除和定期删除

惰性删除:当过期后再次使用到的时候再删除key,对CPU友好,但可能会有很多过期key没删到。

定期删除:定期的检查内存里过期的key进行删除,对内存友好,redis会限制删除的时长和频率,尽量不影响CPU的执行。

redis采用的是惰性删除+定期删除的策略。

常用的内存淘汰策略如下:

内存足的情况下

1、LRU:从已经设置过期时间的数据集里找出最近最少使用的数据淘汰

2、TTL:从已经设置过期时间的数据集里找出快过期的数据淘汰

3、RANDOM:从已经设置过期时间的数据集里随机淘汰

4、LFU:从已经设置过期时间的数据集里找出最不经常使用的数据淘汰

内存不足的情况下

1、LRU:从所有数据集里找出最近最少使用的数据淘汰

2、RANDOM:从所有数据集里随机淘汰

3、拒绝策略,内存不足的情况下,禁止新数据插入,一般不用。

4、LFU:从所有数据集里找出最不经常使用的数据淘汰

LRU和LFU的区别

LRU是看最近一时刻内的使用时间排序,找出最近最少使用的。

LFU是看最近一段时间内的使用频率,找出最不经常使用的。

redis集群有几种方式?

主从模式、哨兵模式、Cluster模式。

主从模式:实现读写分离、数据备份。但是这不是高可用的。

哨兵模式:在主从的基础上增加一个哨兵对整个redis集群进行监控,但是由于只有一个主节点,依然会有写入瓶颈。

Cluster模式:不仅提供了高可用的手段,数据分片存储在各个节点,支持高并发的写入和读取。

redis哨兵模式讲一下,怎么选主?

哨兵模式原理:

哨兵对主从redis进行监控,心跳检查是否存活,如果不存活,就会对节点进行故障转移,进行选主。

选主主要有三个角色:一个leader领导,一个候选人,一个群众。在leader死亡的时候,候选人会广播所有人投票给自己,这时候就看网络波动之类的,最后候选人如果没选上就成群众,选上了就是leader。

消息队列

RabbitMQ和RocketMQ的区别?

RabbitMQ消息挤压怎么处理?

RabbitMQ高可用怎么实现,集群模式?

怎么保证消息的可靠性传输(如何处理消息丢失的问题)?

怎么保证消息的有序性?

搜索引擎

ElasticSearch的倒排索引是什么?

ElasticSearch如何防止脑裂?

分布式

讲一下分布式事务?

跨语言事务怎么实现?

nacos和eureka的区别?

CAP理论讲一下?

PAXOS算法讲一下?

系统设计

如何设计一个秒杀系统?

1、高可用

秒杀得单独一个服务,并且避免单机故障,需要搭建集群,所用到的中间件如redis也得搭建集群。

服务要做限流熔断,比如用sentinel。

秒杀的接口路径要md5加密,防止泄露,提前请求。

2、高性能

动静分离,静态数据存放在CDN或者Nginx内。

热点数据 商品存放在redis内。

使用mq异步创建订单或者发送短信。

3、数据一致性

接口设计成非幂等性

库存扣减使用redis的lua脚本来实现。

前端按钮控制。

如何设计一个非幂等性接口?

幂等性场景:比如前端重复提交、接口超时重试机制、mq消息重复消费。

1、基于悲观锁,譬如数据库内的select xxx for update;

2、基于乐观锁,数据库加个版本号 version

3、基于token+redis来实现,第一步获取token存入redis,第二步调用接口的时候都判断是否存在token,判断要用delete,不能用get再判断,那不是原子性的;

4、基于唯一索引,比如订单号只能存在一个。

5、基于锁实现,锁住一整块代码或者方法,这样只有一个请求调用完下个请求才进来。

如何设计一个数据库连接池?

项目怎么进行技术选型?

从用户体量和业务场景和技术团队进行思考。

从架构上说,并非所有项目都要搭建微服务的架构

单体架构的好处就是快速开发,成型快,系统调用都在进程内,调试方便,适合初创团队;微服务架构适合用户体量大,业务场景复杂,可以各个团队负责自己的模块开发,搭建集群也可以保证高可用。

对于数据库的选择:可以选择MySQL,对于银行等业务可以使用oracle(商业闭源,成熟,更在乎数据的一致性),对于性能要求极高的可以使用NewSQL数据库 TiDB之类的,Redis、ES之类的。

对于接口性能优化、系统之间解耦合,我们可以采用MQ,比如RabbitMQ、RocketMQ之类的,可以参考我们团队的技术背景。

总结:以需求为第一目标,在能完成需求的情况下,选择学习成本最低的,而且是大公司的解决方案最佳。

代码评审规范?

描述下责任链模式?

排查问题

CPU100%怎么排查?

锁没释放排查思路?

使用jps找到对应进程,用jstack dump出log文件,如果死锁 搜索deadlock关键字就可以找到对应死锁的位置。

还可以使用jvisualVM导入这个java进程,也可以看到类似jstack的dump文件,找到对应的代码位置。

项目问题

各个平台(如淘宝、京东)的调用api的参数加解密算法分别有什么?

验签的话,一般大平台会有自己的sdk,创建对应的client把appkey和secret和token传进去就好了。

参数验签 大部分是把参数存成k-v键值对的map形式,按key的ascii码进行升序或者降序,然后拼接key和value再把secret拼接在前后,进行md5或者base64编码加密。

对称加密和非对称加密算法是什么?有哪些?

对称加密是发送方和接收方都用同一个密钥加解密,常见的算法有DES。

优点就是加密快 体积小,缺点就是密钥泄露不安全。

非对称加密就是公钥加密的数据只能私钥解密,私钥加密的数据只能公钥解密,常见的算法有RSA。

优点就是安全,即使公钥和密文被截获,他们没有私钥也无法解密,缺点就是效率低。

对账系统的T+1/T+7是什么?

交易日后一天结算,交易日后七天结算。

项目中用到了什么设计模式?

策略 工厂 模板 单例。

前端问题

vue怎么向后端发起请求?

使用axios进行请求,axios是基于promise的http封装,ajax和axios都实现的局部数据的刷新。

vue双向绑定是怎么实现的?

vue的生命周期?

基础问题

Linux常用命令有哪些?

top查看cpu、内存等信息;

ps看瞬时的进程状态;

jps查看java进程,线程问题用jstack、内存问题用jmap;

sed对文件进行筛选 替换;

grep 管道,过滤一些内容;

chmod,修改文件权限;

netstat查看端口占用;

free 查看内存;

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值