面试中被问到的问题(一)

都不算难,但如果没下功课的话临时是回答不上来的,个人水平有限,有错误欢迎指正

1.Springboot启动流程

这个比较长,我直接贴一个别人的贴子:https://blog.csdn.net/weixin_55697693/article/details/130358395

2.ArrayList与HashMap扩容机制

简单来说,ArrayList扩容是每次扩容1.5倍,源码里是原长度 + 原长度的一半。HashMap扩容是每次扩容两倍,源码是长度左移一位(< < 1)。

具体的源代码可以看这个帖子:https://blog.csdn.net/CSDN_WYL2016/article/details/107682707

  • 那么为什么要这么扩呢?

简单来说,都是摸索出来的一个内存使用和性能之间的数字,数字大了浪费内存,数字小了频繁扩容浪费时间和空间开销。HashMap靠移位扩容,里边的数据桶也方便通过位运算来重新分配(俗称散列)。ArrayList的扩容倍数是可以更改的。

3.写一句SQL

  • 背景:

有表Student,表的结构如图:

name(pk)coursescore
张三语文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.csdn.net/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;**这种比较常用。

方法五:用户一般喜欢点前十页,那就把前十页放进缓存——这种方法虽然听着很抽象,但是确实有用。

  • 16
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值