都不算难,但如果没下功课的话临时是回答不上来的,个人水平有限,有错误欢迎指正
1.Springboot启动流程
这个比较长,我直接贴一个别人的贴子:https://blog.youkuaiyun.com/weixin_55697693/article/details/130358395
2.ArrayList与HashMap扩容机制
简单来说,ArrayList扩容是每次扩容1.5倍,源码里是原长度 + 原长度的一半。HashMap扩容是每次扩容两倍,源码是长度左移一位(< < 1)。
具体的源代码可以看这个帖子:https://blog.youkuaiyun.com/优快云_WYL2016/article/details/107682707
- 那么为什么要这么扩呢?
简单来说,都是摸索出来的一个内存使用和性能之间的数字,数字大了浪费内存,数字小了频繁扩容浪费时间和空间开销。HashMap靠移位扩容,里边的数据桶也方便通过位运算来重新分配(俗称散列)。ArrayList的扩容倍数是可以更改的。
3.写一句SQL
- 背景:
有表Student,表的结构如图:
name(pk) | course | score |
---|---|---|
张三 | 语文 | 90 |
张三 | 数学 | 0 |
李四 | 语文 | 80 |
李四 | 数学 | 90 |
李四 | 英语 | 100 |
名称作为标识,其中科目不固定。
- 要求
写一句SQL,没有性能要求,要查询出所有平均分超过60的学生名。
- 答案
select name from student
group by name
having avg(score) > 60
- 解析
这题的难点在于:需要按学生名分组,以及分组之后计算平均值,好在SQL里提供了HAVING子句用以处理这种情况。我们只需要先使用GROUP BY分组,再使用HAVING筛选就行了。
- 扩展
SQL中的函数,包括COUNT、AVG、MAX、MIN、HAVING、EXISTS等常用函数。
4.不引入第三个变量,交换ab两个数的值
- 背景
有ab两个数,能在不引入第三个变量的情况下交换两个数吗
- 答案
这个是经典面试题,再怎么也得记住思路:通过相加相减方式存储
//最常见的法子
a = a + b;
b = a - b;
a = a - b;
//与之类似的
a = a - b;
b = a + b;
a = b - a;
//还有与之类似的乘法也可以,不过乘法更容易爆值
//高级一点的就是异或 也就是^
//异或具体可以自行查阅 本次主要使用的是异或运算的自反:a ^ b ^ a = b
a = a ^ b;
b = a ^ b;
a = a ^ b;
5.事务隔离的级别
这个其实很简单,4个级别:
- RU,READ-UNCOMMITTED,读未提交。意思就是我开一个事务,他开一个事务,他在事务里修改了值,但还没提交,我事务里就能查到他修改后的值。毫无疑问,肉眼可见的容易导致读到脏数据(脏读)、两次查询数据不一样(不可重复读)、两次查询的数据行数不一样(幻读)。用的少,安全性也不是很高。
- RC,READ-COMMITTED,读已提交。同样是两个事务,他开了事务,修改完数据,提交成功了,我这再去读才能读到改过的数据。这样别人的脏数据就读不到了,但还是不可重复读,幻读。
- RR,READ-REPEAT,可重复读。我这个事务不管怎么查数据跟数据行数都是一样的,不管别人事务里怎么增删改。防脏读、幻读、可以重复读。缺点就是有锁,并发效率就下去了。
- SR(SERIALIZABLE ),串行化。事务跟事务之间的并发跟排了队一样顺序执行,比可重复读更狠的锁,防脏读、幻读、可以重复读。但是锁太狠了,效率非常低。
所以一般默认都是可重复读这个级别。
扩展
数据库的事务隔离级别有4种,但Spring的事务管理种提供了5种,多的一种是什么呢?
READ_UNCOMMITTED:读未提交(最低级别,可出现脏读、幻读、不可重复读等问题)。
READ_COMMITTED:读已提交(默认级别,解决了脏读问题,但可能出现幻读和不可重复读问题)。
REPEATABLE_READ:可重复读(解决了脏读和不可重复读问题,但可能出现幻读问题)。
SERIALIZABLE:序列化(最高级别,解决了脏读、幻读和不可重复读问题,但性能较低)。
DEFAULT:使用底层数据库默认的隔离级别。
多了一种使用数据库默认隔离级别的级别,当然这只是程序里的隔离级别,通常我们提到事务的隔离级别时默认是指数据库。
Spring里为了处理跟事务有关的A方法中调用B方法,B方法要怎么处理事务的情况,还定义了7种事务传播级别:
REQUIRED(默认):如果当前存在事务,则加入该事务,如果不存在则新建一个事务。
SUPPORTS:如果当前存在事务,则加入该事务,如果不存在则以非事务的方式执行。
MANDATORY:强制当前存在事务,如果不存在则抛出异常。
REQUIRES_NEW:每次都新建一个事务,如果当前存在事务,则挂起当前事务。
NOT_SUPPORTED:以非事务的方式执行,如果当前存在事务,则挂起当前事务。
NEVER:以非事务的方式执行,如果当前存在事务,则抛出异常。
NESTED:如果当前存在事务,则在该事务的子事务中执行,如果不存在则新建一个事务。
如果AB方法都定义了事务传播级别,那就有7 x 7 的组合方式,具体可以查阅相关博客,这里就不提了。
6.Redis的数据类型
看到个帖子讲的很清楚:https://blog.youkuaiyun.com/qq_34625397/article/details/139117176
7.ArrayList去重
一般不考虑空间问题的话,最简单粗暴的方法就是使用HashSet,将ArrayList的元素丢进HashSet:
Set<Object> hashSet = new HashSet<>(list);
List<Object> newList = new ArrayList<>(hashSet);
如果想保留原顺序的话,可以接一下:
Set<Object> hashSet = new HashSet<>();
List<Object> newList = new ArrayList<>();
for (Iterator<Object> iter = list.iterator(); iter.hasNext();) {
Object element = iter.next();
if (hashSet.add(element)) {
newList.add(element);
}
}
需要排序那就用TreeSet:
Set<Object> treeSet = new TreeSet<>(list);
List<Object> newList = new ArrayList<>(treeSet);
搞俩List双循环接也不是不行:
for (int i = 0; i < list.size(); i++) {
if (!newList.contains(oldlist.get(i))) {
newList.add(oldlist.get(i));
}
}
如果允许调用API的话,使用jdk1.8(也是市面上常用的jdk版本)的流编程也是很棒的:
newlist = list.stream().distinct().collect(Collectors.toList());
不过stream 去重的效率最低,效率最高的是俩List循环。
原帖可见:https://juejin.cn/post/7026353737241362468
8.MYSQL分页查询越来越慢该怎么办
- 背景:MYSQL数据库分页查询,页数越多越慢
- 原因:MYSQL分页查询机制实际上是先把偏移量前的数据查出来再丢掉,举个例子就是
SELECT * FROM table LIMIT 2000,25
这个SQL实际上查出来了2025条数据,然后把前2000条抛掉。这样的话很显然查询速度会越来越慢。
- 解决方案
方法一:既然是因为大数据量慢,那就优化查询,请老朋友索引来。
方法二:数据量太大?那就直接纵向横向分表。
方法三:加钱,买更好的设备。(一般来说客户可听不得这句话)
方法四:可以想办法让sql不去查前面那些要丢掉的东西,比如在ID有序的情况下,这一页开头的ID是123,那就可以把SQL写成**SELECT * FROM users WHERE id > 122 ORDER BY id LIMIT 10;**这种比较常用。
方法五:用户一般喜欢点前十页,那就把前十页放进缓存——这种方法虽然听着很抽象,但是确实有用。