文章目录
-
- 前言
- 面试的问题
-
- 自我介绍太过简单
- 接口和抽象类的区别
- HashMap和HashTable区别
- 讲讲HashMap底层原理
- 简单描述你实习的这个项目
- 前端项目你是自己搭建的还是用现成的
- 前端你怎么打包
- 简单说说你用的git操作
- 你对SpringMVC了解多少,讲讲执行流程
- Mybatis你了解多少
- 垃圾收集有哪些算法/li>
- 你对MySQL了解多少/li>
- 你有把自己的项目部署到其他地方吗
- 能说说负载均衡吗/li>
- 简单讲讲你的酒店项目
- 除了Java你还学习了哪些其他语言吗
- 专业以及职业规划问题
- 第二家
-
- 常见的垃圾回收器有哪些/li>
- JDK8新特性
- 什么是集合,集合有哪些种类/li>
- List想要线程安全应该怎么用/li>
- HashMap
- Java的线程池
- 以MySQL为例Linux下如何排查问题/li>
- 如何处理慢查询/li>
- MySQL优化
- 索引有哪些数据结构及其优劣势
- SQL在MySQL里是如何执行的
- MyBatis和MyBatisPlus在使用上有什么差异
- Mybatis批量操作
- 关系型数据库和非关系型数据库一般都存什么数据
- Redis有哪些数据类型
- Redis缓存雪崩了解过吗
- 后期的职业规划, 是打算吃苦耐劳走技术路线还是走管理
- 结语
前言
经过半个多月的海投和疯狂笔试与学习,终于在本周陆续迎来了两场面试,喜忧参半。两场面试自己录音之后复盘了好几天,有些地方达到企业要求,但同时也发现自己有太多的不足,长期与机器打交道好像自己丧失了一些交流沟通的能力,有些地方表达的还不够自信,举止不够大方得体,总之两场面试下来感觉很舒服,真的很感谢这些企业在这种环境下还可以给我这么宝贵的面试机会,也同时希望将自己在面试中的不足给大家分享一下,大家自己真实面对的时候就可以更加游刃有余。
面试的问题
自我介绍太过简单
你好,我叫xxx,目前就读于xxx,是一名xx专业大四学生,本专业开设了高等数学,线性代数,计算机基础,信息检索,多媒体技术及其应用等课程,后来自己也尝试去听我们学校计算机专业的课程,后来经过各种尝试发现线上课师资更好,加上自我控制能力还不错,就坚持学了下去,中间一直学习把计算机科班的课基本上都学了一遍并且后续不断深入进行体系化的学习,现在掌握Java的基本知识和企业开发的一些像Springboot、Vue、Mybatis、MyBatisPlus、Hibernate等技术栈;用过Mysql、Oracle等数据库;有像Redis、RabbitMQ等中间件的使用经验,并且有相关实际项目操作经验,上一段在xx的实习过程中能完成技术组长和项目经理布置的开发任务。相信我也是具备基本的开发能力能满足企业的要求,也很感谢贵公司给我这次面试机会
接口和抽象类的区别
- 接口的方法默认是public,所有方法在接口中不能有实现(Java8开始接口方法可以有默认实现),而抽象类可以有非抽象的方法
- 接口中除了static、final变量,不能有其他变量,而抽象类中则不一定
- 一个类可以实现多个接口,但只能实现一个抽象类。接口本身可以通过extends关键字扩展多个接口
- 接口方法默认是public,抽象方法可以有public、protected和default这些修饰符(抽象方法就是为了被重写所以不能使用private关键字修饰!)
- 从设计层面来说,抽象是对类的抽象,是一种模板设计,而接口是对行为的抽象,是一种行为的规范
- 在 JDK 7 或更早版本中,接???只能有常量变量和抽象?法。这些接??法必须由选择实 现接?的类实现
- JDK 8 的时候接?可以有默认?法和静态?法功能
- JDK 9 在接?中引?了私有?法和私有静态?法
HashMap和HashTable区别
HashMap | HashTable | |
---|---|---|
线程安全 | 否 | 是 |
效率 | 高 | 低,基本被淘汰 |
Null键和Null值的支持 | 唯一Null键,多个Null值 | NPE |
初始容量大小和每次扩充容量大小 | 16,2的幂次倍 | 11(也可以指定),2n+1, |
底层数据结构 | 数组+链表或者红黑树 | 数组+链表 |
讲讲HashMap底层原理
JDK1.8 之前 HashMap 底层是 数组和链表 结合在?起使?也就是 链表散列。HashMap 通过 key 的 hashCode 经过扰动函数处理过后得到 hash 值,然后通过 (n – 1) & hash 判断当前元素存放的位置(这?的 n 指的是数组的?度),如果当前位置存在元素的话,就判断该元素与要存?的元素的 hash 值以及 key 是否相同,如果相同的话,直接覆盖,不相同就通过拉链法解决冲突
所谓扰动函数指的就是 HashMap 的 hash ?法。使? hash ?法也就是扰动函数是为了防?? 些实现?较差的 hashCode() ?法 换句话说使?扰动函数之后可以减少碰撞 。 所谓 “拉链法” 就是:将链表和数组相结合。也就是说创建?个链表数组,数组中每?格就是?个链表。若遇到哈希冲突,则将冲突的值加到链表中即可
HashMap的长度为什么是2的幂次方
为了能让 HashMap 存取?效,尽量较少碰撞,也就是要尽量把数据分配均匀。我们上?也讲到 了过了,Hash 值的范围值-2147483648到2147483647,前后加起来?概40亿的映射空间,只要 哈希函数映射得?较均匀松散,?般应?是很难出现碰撞的。但问题是?个40亿?度的数组,内存是放不下的。所以这个散列值是不能直接拿来?的。?之前还要先做对数组的?度取模运算, 得到的余数才能?来要存放的位置也就是对应的数组下标。这个数组下标的计算?法是“ (n – 1) & hash ”。(n代表数组?度)。这也就解释了 HashMap 的?度为什么是2的幂次?
这个算法应该如何设计/strong>
我们?先可能会想到采?%取余的操作来实现。但是,重点来了:“取余(%)操作中如果除数是2 的幂次则等价于与其除数减?的与(&)操作(也就是说 hash%length==hash&(length-1)的前提 是 length 是2的 n 次?;)。” 并且 采??进制位操作 &,相对于%能够提?运算效率,这就解 释了 HashMap 的?度为什么是2的幂次?
简单描述你实习的这个项目
前端项目你是自己搭建的还是用现成的
前端你怎么打包
npm run build ——> 生成dist的文件夹 ——> 用Nginx(启动:cd/usr/local/nginx/sbin ./nginx) ——>将dist文件传过去 ——> 服务器中 /usr/local/nginx/conf/nginx.conf
- 对 CPU 资源敏感
- ?法处理浮动垃圾
- 它使?的回收算法-“标记-清除”算法会导致收集结束时会有?量空间碎?产?
G1: G1 (Garbage-First) 是?款?向服务器的垃圾收集器,主要针对配备多颗处理器及?容量内存的机器. 以极?概率满? GC 停顿时间要求的同时,还具备?吞吐量性能特征。 被视为 JDK1.7 中 HotSpot 虚拟机的?个重要进化特征。它具备以下特点 :
- 并?与并发:G1 能充分利? CPU、多核环境下的硬件优势,使?多个 CPU(CPU 或者 CPU 核?)来缩短 STW 停顿时间。部分其他收集器原本需要停顿 Java 线程执?的 GC 动作,G1收集器仍然可以通过并发的?式让 java 程序继续执?
- 分代收集:虽然 G1 可以不需要其他收集器配合就能独?管理整个 GC 堆,但是还是保留了 分代的概念。
- 空间整合:与 CMS 的“标记–清理”算法不同,G1 从整体来看是基于“标记整理”算法实现的 收集器;从局部上来看是基于“复制”算法实现的
- 可预测的停顿:这是 G1 相对于 CMS 的另?个?优势,降低停顿时间是 G1 和 CMS 共同 的关注点,但 G1 除了追求低停顿外,还能建?可预测的停顿时间模型,能让使?者明确指 定在?个?度为 M 毫秒的时间?段内
- G1 收集器的运作?致分为以下?个步骤: 初始标记 并发标记 最终标记 筛选回收
- G1 收集器在后台维护了?个优先列表,每次根据允许的收集时间,优先选择回收价值最?的 Region(这也就是它的名字 Garbage-First 的由来)。这种使? Region 划分内存空间以及有优先级的区域回收?式,保证了 G1 收集器在有限时间内可以尽可能?的收集效率(把内存化整为 零)。
ZGC收集器: 与 CMS 中的 ParNew 和 G1 类似,ZGC 也采?标记-复制算法,不过 ZGC 对该算法做了重?改 进。 在 ZGC 中出现 Stop The World 的情况会更少! 详情可以看 : ZGC
JDK8新特性
-
基本函数接口: 函数式接口(Functional Interface)就是一个有且仅有一个抽象方法,但是可以有多个非抽象方法的接口。 函数式接口可以被隐式转换为 lambda 表达式。 基本的函数式接口主要有四个
- Supplier 生产者:无输入,生产一个 T 类型的值;接口仅包含一个无参的方法: T get() 。用来获取一个泛型参数指定类型的对象数据
- Consumer 消费者:输入一个 T 类型的值,无输出;对给定参数执行消费操作
-
Function
函数 :输入一个 T 类型的值,返回一个 R 类型的值; - Predicate 断言:输入一个 T 类型的值,返回 true/false
-
Lambda表达式:Lambda它其实是匿名函数,通过约定好怎么传入参数,怎么返回参数,由编译器负责参数类型的猜测并执行结果,Lambda表达式的基本语法
- (parameters) ——> expression 即”->”操作符将Lambda表达式分为两个部分:左侧为参数列表,右侧为Lambda体。每一个Lambda表达式的返回体都是一个函数式编程的接口
-
Optional类的使用:Optional类的作用主要是为了解决空指针的问题,通过对结果的包装,并使用方法来代替if判断,为流式编程打下了良好的基础
-
Stream流式编程:Stream API借助Lambda表达式,提供串行和并行两种模式进行汇聚操作,并行模式能够充分利用多核处理器的优势,使用 fork/join 来拆分任务和加速处理过程
-
方法引用(::双冒 操作符):简单来说就是一个Lambda表达式,方法引用提供了一种引用而不执行方法的方式,运行时方法引用会创建一个函数式接口的实例
什么是集合,集合有哪些种类/h3>
List想要线程安全应该怎么用/h3>
- 使用java.util.Vector
- 使用java.util.Collections.synchronizedList(list)
- java.util.concurrent.CopyOnWriteArrayList 读写分离的思想,写上锁,读无锁。写入时,加锁(利用了java.util.concurrent.locks.ReentrantLock上锁),复制原数组(并且数组长度+1,赋值数组末尾元素为要新增的元素),再更新数组的引用,解锁
HashMap
Java的线程池
- 使用java.util.Vector
- 使用java.util.Collections.synchronizedList(list)
- java.util.concurrent.CopyOnWriteArrayList 读写分离的思想,写上锁,读无锁。写入时,加锁(利用了java.util.concurrent.locks.ReentrantLock上锁),复制原数组(并且数组长度+1,赋值数组末尾元素为要新增的元素),再更新数组的引用,解锁
HashMap
Java的线程池
池化技术相??家已经屡?不鲜了,线程池、数据库连接池、Http 连接池等等都是对这个思想的应?。池化技术的思想主要是为了减少每次获取资源的消耗,提?对资源的利?率 。线程池提供了?种限制和管理资源(包括执??个任务)。 每个线程池还维护?些基本统计信息,例如已完成任务的数量
使用线程池的好处
- 降低资源消耗:通过重复利用已创建的线程降低线程创建和消耗造成的消耗
- 提高响应速度:当任务到达时,任务可以不需要得等到线程创建就能立即执行
- 提高线程的可管理性:线程是稀缺资源,如果无限制的创建,不仅会消耗系统资源,还会降低系统的稳定性,使用线程池可以进行统一的分配,调优和监控
线程池核心参数:
- corePoolSize:核心线程数线程数定义了最小可以同时运行的线程数量
- maximumPoolSize:当队列中存放的任务达到队列容量的时候,当前可以同时运行的线程数量变为最大线程数
- workQueue:当新任务来的时候会先判断当前运行的线程数量是否达到核心线程数,如果达到的话,新任务就会被存放在队列中
- keepAliveTime:当线程池中的线程数量大于的时候,如果这时没有新的任务提交,核心线程数不会立即销毁,而是会等待,直到等待的时间超过了keepAliveTime才会被回收销毁
- unit:参数的时间单位
- threadFactory:executor创建新线程的时候会用到
- handler:饱和策略
线程池有哪些工作队列
- ArrayBlockingQueue 数组型阻塞队列: 初始化一定容量的数组,使用一个重入锁,默认使用非公平锁,入队和出队共用一个锁,互斥 是有界设计,如果容量满无法继续添加元素直至有元素被移除; 使用时开辟一段连续的内存,如果初始化容量过大容易造成资源浪费,过小易添加失败
- LinkedBlockingQueue 链表型阻塞队列: 内部使用节点关联,会产生多一点内存占用; 使用两个重入锁分别控制元素的入队和出队,用Condition进行线程间的唤醒和等待; 有边界的,再默认构造方法中容量是,非连续性内存空间
- DelayQueue 延时队列: 无边界设计,添加(put)不阻塞,移除阻塞, 元素都有一个过期时间,取元素只有过期的才会被取出
- SynchroniousQueue 同步队列: 内部容量是0, 每次删除操作都要等待插入操作; 每次插入操作都要等待删除操作 一个元素,一旦有了插入线程和移除线程,那么很快由插入线程移交给移除线程,这个容器相当于通道,本身不存储元素, 在多任务队列,是最快的处理任务方式
- PriorityBlockingQueue 优先阻塞队列: 无边界设计,但容量实际是依靠系统资源影响; 添加元素,如果超过1,则进行优先级排序
饱和策略定义: 如果当前同时运行的线程数量达到最大线程数量并且队列也已经被放满了任务时,定义一些策略:
- : 抛出来拒绝新任务的处理
- : 调用执行自己的线程运行任务,你不会任务请求.但是这种策略会降低对于新任务提交速度,影响程序的整体性能.另外,这个策略喜欢增加队列容量.如果你的应用程序可以承受此延迟并且不能丢弃任何一个任务请求的话,你可以选择这个策略
- : 不处理新任务,直接丢弃掉
- : 此策略将丢弃最早的未处理的任务请求
MySQL中left join的优化
- 小表驱动大表
- 用子查询代替left join,依据join的原理,减少了驱动表的数据量,从而减少访问匹配表的次数.
- 不使用group by减少了cpu对分组数据的处理,分组的操作可以理解为数据库引擎查询数据出来的过程,当然是越少越好
- 因为group by的优先级是在limit之前的,所以之前是对查询的所有数据先进行分组,然后取十条.优化后,先取十条再进行sum()操作,优化力度还是挺大的
以MySQL为例Linux下如何排查问题/h3>
类似提问方式:如果线上环境出现问题比如 站卡顿重则瘫痪 如何是好/p>
—>linux—>mysql/redis/nacos/sentinel/sluth—>可以从以上提到的技术点中选择一个自己熟悉单技术点进行分析
以mysql为例
- 架构层面 是否使用主从
- 表结构层面 是否满足常规的表设计规范(大量冗余字段会导致查询会变得很复杂)
- sql语句层面(?)
前提: 由于慢查询日志记录默认是关闭的,所以开启数据库mysql的慢查询记录的功能 从慢查询日志中去获取哪些sql语句时慢查询 默认10S ,从中获取到sql语句进行分析
explain 分析一条sql

- Id: 执行顺序 如果单表的话,无参考价值,如果是关联查询,会据此判断主表 从表
- Type: All 未创建索引 const 常量 ref 其他索引 eq_ref 主键索引
- Key: 实际是到用到索引的字段
- Key_len: 索引字段数据结构所使用的长度与是否有默认值null以及对应字段到数据类型有关,有一个理论值,实际使用值也即key_len的值
- Rows: 检索的行数 与查询返回的行数无关
- Extra: 常见的值: usingfilesort 使用磁盘排序算法进行排序,事关排序分组的字段是否使用索引的核心参考值
还可能这样去提问:sql语句中哪些位置适合建索引/索引建立在哪个位置/strong>
Select id,name,age from user where id=1 and name=”xxx” order by age
总结: 查询字段 查询条件(最常用) 排序/分组字段
补充: 如何判断是数据库的问题可以借助于top命令
如何处理慢查询/h3>
在业务系统中,除了使用主键进行的查询,其他的都会在测试库上测试其耗时,慢查询的统计主要由运维在做,会定期将业务中的慢查询反馈给我们。慢查询的优化首先要搞明白慢的原因是什么**是查询条件没有命中索引加载了不需要的数据列是数据量太大**所以优化也是针对这三个方向来的
- 首先分析语句,看看是否加载了额外的数据,可能是查询了多余的行并且抛弃掉了,可能是加载了许多结果中并不需要的列,对语句进行分析以及重写。
- 分析语句的执行计划,然后获得其使用索引的情况,之后修改语句或者修改索引,使得语句可以尽可能的命中索引。
- 如果对语句的优化已经无法进行,可以考虑表中的数据量是否太大,如果是的话可以进行横向或者纵向的分表
另一种说法SQL执行慢的情况分析
- 大多数情况下很正常,偶尔很慢,则有如下原因
- 数据库在刷新脏页, 例如 redo log 写满了需要同步到磁盘 内存不够用 MySQL认为系统”空闲”的时候 MySQL正常关闭的时候
- 执行的时候遇到锁, 如表锁 行锁 show processlist 命令查看当前状态(太重要了)
- 这条SQL语句一直执行的很慢, 则有如下原因
- 没有用上索引:例如该字段没有索引;由于对字段进行运算、函数操作导致无法用索引
- 数据库选错了索引
深入一点来了解慢查询
-
慢查询,顾名思义,执行很慢的查询。有多慢过long_query_time参数设定的时间阈值(默认10s),就被认为是慢的,是需要优化的。慢查询被记录在慢查询日志里。慢查询日志默认是不开启的。如果需要优化SQL语句,就可以开启这个功能,它可以让你很容易地知道哪些语句是需要优化的。
1??;查询是否开启慢查询日志
【开启慢查询sql:set global slow_query_log = 1/on;】
【关闭慢查询sql:set global slow_query_log = 0/off;】
2??;查询未使用索引是否开启记录慢查询日志
【开启记录未使用索引sql:set global log_queries_not_using_indexes=1/on】
【关闭记录未使用索引sql:set global log_queries_not_using_indexes=1/off】
3??;查询超过多少秒的记录到慢查询日志中
【设置超1秒就记录慢查询sql:set global long_query_time= 1;设置超1秒就记录】 -
慢查询的配置文件 my.cnf
在MySQL的配置文件my.cnf中写上:long_query_time = 10
log-slow-queries = /var/lib/mysql/mysql-slow.loglong_query_time是指执行超过多久的SQL会被日志记录下来,这里是10 秒。
log-slow-queries设置把日志写在哪里。为空的时候,系统会给慢查询日志赋予主机名,并加上slow.log。如果设置了参数log-long-format,那么所有没有使用索引的查询也将被记录。
这是一个非常有用的日志。它对于性能的影响不大(假设所有查询都很快),并且强调了那些最需要注意的查询(丢失了索引或索引没有得到最佳应用)
-
慢查询解读
- 第一行:记录时间
- 第二行:用户名 、用户的IP信息、线程ID
- 第三行:执行花费的时间【单位:毫秒】、执行获得锁的时间、获得的结果行数、扫描的数据行数
- 第四行:这SQL执行的时间戳
- 第五行:具体的SQL语句
MySQL优化
- 条件尽量选择较小的列
- 将where中用的比较频繁的字段建立索引
- 将select子句中避免使用 “*”
- 避免在索引列上使用计算 not in 和 等操作
- 当只需要一行数据的时候用 limit 1
- 保证单表数据不超过200w, 适时分割表. 针对查询较慢的语句, 可以使用explain来分析该语句的具体执行情况
- 避免改变索引列的类型
- 选择最有效的表名顺序, from子句中写在最后的表是基础表,将被最先处理, 在from子句中包含多个表的情况下,你必须选择记录条数最少的表作为基础表
- 尽量缩小子查询的结果
如何优化下面的语句/strong>
select * from admin left join log on admin.admin_id = log.admin_id where log.admin_id>10
优化为:select * from (select * from admin where admin_id>10) T1 lef join log on T1.admin_id = log.admin_id。
使用 JOIN 时候,应该用小的结果驱动大的结果(left join 左边表结果尽量小如果有条件应该放到左边先处理, right join 同理反向),同时尽量把牵涉到多表联合的查询拆分多个 query(多个连表查询效率低,容易到之后锁表和阻塞)
MySQL高性能优化规范建议: MySQL高性能优化规范建议,速度收藏 (qq.com)
后端程序员必备:书写高质量SQL的30条建议 (qq.com)
索引有哪些数据结构及其优劣势
MySQL索引使?的数据结构主要有BTree索引 和 哈希索引 。对于哈希索引来说,底层的数据结构就是哈希表,因此在绝?多数需求为单条记录查询的时候,可以选择哈希索引,查询性能最快;其余?部分场景,建议选择BTree索引
Hash索引的缺点
- Hash冲突问题: 也就是说多个不同的 key 最后得到的 index 相同。通常情况下,我们常用的解决办法是 链地址法。链地址法就是将哈希冲突数据存放在链表中
- 不支持顺序和范围查询
MySQL的BTree索引使?的是B树中的B+Tree,但对于主要的两种存储引擎的实现?式是不同 的。
- MyISAM: B+Tree叶节点的data域存放的是数据记录的地址。在索引检索的时候,?先按照 B+Tree搜索算法搜索索引,如果指定的Key存在,则取出其 data 域的值,然后以 data 域的 值为地址读取相应的数据记录。这被称为“?聚簇索引”。
- InnoDB: 其数据?件本身就是索引?件。相?MyISAM,索引?件和数据?件是分离的,其 表数据?件本身就是按B+Tree组织的?个索引结构,树的叶节点data域保存了完整的数据记录。这个索引的key是数据表的主键,因此InnoDB表数据?件本身就是主索引。这被称为“聚 簇索引(或聚集索引)”。?其余的索引都作为辅助索引,辅助索引的data域存储相应记录主 键的值?不是地址,这也是和MyISAM不同的地?。在根据主索引搜索时,直接找到key所在的节点即可取出数据;在根据辅助索引查找时,则需要先取出主键的值,再??遍主索引。 因此,在设计表的时候,不建议使?过?的字段作为主键,也不建议使??单调的字段 作为主键,这样会造成主索引频繁分裂
B树 & B+树的异同
- B 树的所有节点既存放键(key) 也存放 数据(data),而 B+树只有叶子节点存放 key 和 data,其他内节点只存放 key。
- B 树的叶子节点都是独立的;B+树的叶子节点有一条引用链指向与它相邻的叶子节点。
- B 树的检索的过程相当于对范围内的每个节点的关键字做二分查找,可能还没有到达叶子节点,检索就结束了。而 B+树的检索效率就很稳定了,任何查找都是从根节点到叶子节点的过程,叶子节点的顺序检索很明显
SQL在MySQL里是如何执行的
- MySQL 主要分为 Server 层和引擎层,Server 层主要包括连接器、查询缓存、分析器、优化器、执行器,同时还有一个日志模块(binlog
声明:本站部分文章及图片源自用户投稿,如本站任何资料有侵权请您尽早请联系jinwei@zod.com.cn进行处理,非常感谢!