【面试总结】分享本人作为一个javaweb方向的后端工程师面试问题

目录

一、Spring MVC和Spring boot有啥区别

二、session和cookie的区别

三、复合索引生效失效场景

四、JDK、JRE、JVM的联系与区别

五、如果main方法被声明为private会怎样?

六、&和&&有啥区别

七、char类型的变量能不能存储一个中文?为什么

八、a=a+b和a+=b的区别

九、sql查询出重复值系列

十、雪花算法的id由哪些部分组成?

十一、Spring事务什么时候会失效?

十二、Spring事务的隔离级别有哪些?

十三、B树和B+树的区别

十四、简述java代理模式

十五、简述HashMap的put与get的过程

十六、什么是数据库回表?如何避免数据库回表

十七、redis持久化方案有哪些?

十八、redis主从复制集群是如何保障数据的一致性的呢?

十九、redis是如何实现单线程的

二十、简述mybatis的一级缓存和二级缓存

二十一、ArrayList和LinkedList的区别


一、Spring MVC和Spring boot有啥区别

1.Spring MVC和Spring Boot都是Spring的一部分,且两者都是由IOC提供了依赖注入的容器,由AOP解决面相切面编程(IOC和AOP后续会讲到),然后在此二者基础上衍生的高级功能。SpringMVC的配置比Springboot的配置要复杂得多,各种xml和properties配置文件,处理起来比较繁琐;Springboot他遵循约定优于配置,啥意思呢,就是全都是用默认的配置,这样极大地降低了Spring使用的门槛。

2.Springboot的涉及面比SpringMVC要广,Springboot不仅可以集成Spring MVC,还可以集成JPA Security等,如下图所示:

3.SpringMVC和Sringboot都属于Spring,SpringMVC是基于Spring的一个MVC框架,Springboot是基于Spring的一套快速开发整合包。

总结:Spring 最初利用“工厂模式”( DI )和“代理模式”( AOP )解耦应用组件。大家觉得挺好用,于是按照这种模式搞了一个 MVC 框架(一些用 Spring 解耦的组件),用开发 web 应用( SpringMVC )。然后有发现每次开发都要搞很多依赖,写很多样板代码很麻烦,于是搞了一些懒人整合包( starter ),这套就是 Spring Boot 。

二、session和cookie的区别

1.session是存在服务器端的,cookie是存在浏览器端。

2.cookie相对于session是不安全的。因为cookie是存在浏览器端,别人可以通过分析本地的cookie进行cookie欺骗,如果考虑安全问题,应该使用session。

3.session会在一定时间内存储在服务器上。如果用户量较大,会影响服务器性能,考虑到服务器性能因素,可以使用cookie。

4.一般单个cookie不能超过4k。很多浏览器设置最多保存20个cookie,而session是无限量的。

三、复合索引生效失效场景

复合索引又叫联合索引,是由表中的几个列联合组成的。

复合索引生效需要满足最左前缀原则:(一定要从左到右连续才生效)

即如果复合索引列为a,b,c三列,那么查询条件为a、a,b、a,b,c时,索引生效,b,c、a,c、b、c等不生效(这里的顺序不是where条件后面的先后顺序,而是where条件中是否存在这些列,如果where中只存在a,c列,则索引不生效)

四、JDK、JRE、JVM的联系与区别

JDK,java development kit,java开发工具包;

JRE,java runtime enviroment,java运行环境;

JVM,java virtual machine,java虚拟机;

在JDK安装目录下有一个jre目录,jre目录下面有bin和lib两个文件夹,我们可以认为bin里面就是jvm,lib就是jvm运行所需的类库,jvm和lib结合起来就是jre。

【JDK目录结构】

【JDK-->JRE目录结构】

下面我们由下图来描述一下三者关系:

1.JDK提供开发工具包,编译都是在JDK中进行的(由.java编译为.class),但运行不是在JDK中进行;

2.JRE由JVM和类库组成,

3.JVM借助jre提供的类库,运行.Java程序,java做到跨平台的特性,就是由于不同的平台拥有不同的JVM或JDK,才得以实现。

五、如果main方法被声明为private会怎样?

我们想一下,如果如果类中没有main方法,会怎么样?当然是没啥问题!

如果将修饰符改为private,其实也没啥问题。

如果将修饰符改为private,就相当于我们自己定义了一个方法,名字叫main,当我们运行这个类的时候,会提示我们“找不到main方法,请将main方法定义为public static void main(String[] args)”,因为这里只有我们自定义的一个private main方法,而没有系统默认的public main方法

如果这时我们再写一个public static void main(String[] args),这时候也会报错,因为已经存在了一个private static void main(String[] args),同一个类中不能存在方法名和参数相同的两个方法,因为重载的定义为“方法名相同,参数不同的两个方法叫重载”,所以和修饰符无关。

六、&和&&有啥区别

1.&是位运算符,按二进制进行运算

比如5 & 4就是将5和4分别转换为二进制5(00000101)和二进制4(00000100)进行“与”运算。我们顺便提一下&(与)、“~”(非)、“|”(或)、“^”(异或)四种运算符规则:

【均需要转换成二进制】

运算符运算方式
&(与)两个数转换为二进制,然后从高位开始比较,如果所比较的两个数都是1则为1,否则为0
|(或)两个数转换为二进制,然后从高位开始比较,如果所比较的两个数有一个是1则为1,否则为0
~(非)如果该为为0,结果是1;如果该为是1,结果为0
^(异或)两个数转换为二进制,然后从高位开始比较,两个数相同为0,不同

例:

2.&&是逻辑运算符,比较两个Boolean表达式。

&&运算符对两个Boolean表达式进行比较,当比较的两个均为true时,结果才是true,有一个false,结果就是false。

并且&&运算符具有短路功能,如果比较的前者为false,&&后面将不会运行,如果为true,将会继续运行&&后面的代码;

||运算符同样具有短路功能。

七、char类型的变量能不能存储一个中文?为什么

答案是可以的,但是两个中文不行。因为char占两个字节,一个中文也占两个字节,所以是可以存储的。

八、a=a+b和a+=b的区别

a=a+b是先进行“+”运算,然后进行赋值运算,如果当a(short)与b(int)的类型不同时,会报错,若进行强转,可能会导致精度丢失。

a+=b中,“+=”是一个运算符,而不是两个,所以在运算时 会进行自动类型转换。

总结一下,在两个变量的数据类型一样时:a+=b 和a=a+b 是没有区别的。

但是当两个变量的数据类型不同时,就需要考虑一下数据类型自动转换的问题了。

也就是涉及到精度了。

这里顺便提一下,如何解决浮点型精度丢失的问题。

使用BigDecimal即可,具体使用方法可参考这个链接使用BigDecimal进行精确运算 - chenssy - 博客园

九、sql查询出重复值系列

1、查找多余的重复记录,重复记录是根据字段username进行判断:

SELECT
	*
FROM
	student
WHERE
	username IN (
		SELECT
			username
		FROM
			student
		GROUP BY
			username
		HAVING
			count(username) > 1
	)

查询结果如下:

2、删除表中多余的重复记录,重复记录是根据单个字段username进行判断,并且只保留rowid最小的记录:

十、雪花算法的id由哪些部分组成?

1.符号位,占用1位

2.时间戳,占用41位

3.机器id,占用10位

4.序列号,占用12位

十一、Spring事务什么时候会失效?

  1. bean对象没有被spring容器管理
  2. 方法的访问修饰符不是public
  3. 自身调用问题
  4. 数据源没有配置事务管理器
  5. 数据库不支持事务
  6. 异常被捕获
  7. 异常类型错误或者配置错误

十二、Spring事务的隔离级别有哪些?

Spring事务隔离级别比数据库事务隔离级别多一个default

1) DEFAULT (默认)
这是一个PlatfromTransactionManager默认的隔离级别,使用数据库默认的事务隔离级别。另外四个与JDBC的隔离级别相对应。

2) READ_UNCOMMITTED (读未提交)
这是事务最低的隔离级别,它允许另外一个事务可以看到这个事务未提交的数据。这种隔离级别会产生脏读,不可重复读和幻像读。

3) READ_COMMITTED (读已提交)
保证一个事务修改的数据提交后才能被另外一个事务读取,另外一个事务不能读取该事务未提交的数据。这种事务隔离级别可以避免脏读出现,但是可能会出现不可重复读和幻像读。

4) REPEATABLE_READ (可重复读)
保证在一个事务内,同样的查询语句读到的数据是一样的,不会受到其他事务的update语句影响,可以理解为事务开启那一刻,产生了数据库的快照,读取的数据都是快照中的数据,所以,可重复读又称快照读。这种事务隔离级别可以防止脏读、不可重复读,但是可能出现幻像读(insert、delete)。它除了保证一个事务不能读取另一个事务未提交的数据外,还保证了不可重复读。

5) SERIALIZABLE(串行化)
这是花费最高代价但是最可靠的事务隔离级别,事务被处理为顺序执行。除了防止脏读、不可重复读外,还避免了幻像读。

不可重复读针对同一条数据进行操作,幻读针对的是一批数据进行操作。

幻读和不可重复读都是读取了另一条已经提交的事务(这点就脏读不同),所不同的是不可重复读查询的都是同一个数据项,而幻读针对的是一批数据整体(比如数据的个数)。

十三、B树和B+树的区别

B树:

  • 关键字几何分布在整棵树中,即叶子结点和非叶子结点都存放数据。
  • 搜索有可能在非叶子结点结束。

B+树:

在这里插入图片描述

  • B+树的非叶子结点不保存关键字记录的指针,只进行数据索引,这样使得B+树每个非叶子结点所能保存的关键字大大增加;
  • B+树叶子结点保存了父节点的所有关键字记录的指针,所有数据地址必须要到叶子节点才能获取到,所以每次数据查询的次数都一样的;
  • B+树叶子节点的关键字从小到大有序排列,左边结尾数据都会保存右边节点开始数据的指针。

十四、简述java代理模式

提供了对对象的另外的访问方式,即通过代理对象访问目标对象,这样做的好处就是,可以在目标对象实现的基础上,增强额外的功能操作。代理模式分为静态代理和动态代理。

  • 静态代理做到不修改目标对象功能的前提下,对目标功能进行扩展;但因为代理对象需要与目标对象实现一样的接口,所以会有很多代理类,类太多的时候,一旦接口增加方法,目标对象与代理对象都要维护。
  • JDK的动态代理不需要实现接口,但是目标对象一定要实现节课,否则不能使用动态代理,如果目标对象没有实现接口,就需要使用CGlib。

十五、简述HashMap的put与get的过程

        map.put(k,v)实现原理

1.首先将k,v封装到Node节点当中

2.然后通过哈希算法计算出当前key的hash值

3.再利用哈希函数计算出当前hash值对应的数组索引下标

如果下标没有任何元素,就把这个node添加到这个位置上;如果下标位置有链表,然后在用k和链表上的每一个k进行equals操作;如果所有equals都返回false,就将这个node追加到末尾,如果有一个返回了true,就替换该节点;

jdk1.8以后,如果链表的长度超过了8,那么链表将会转换为红黑树进行存储,以免遍历节点的时候浪费太多时间。

        map.get(k)实现原理

1.先调用k的hashCode方法获取k的hash值,然后通过哈希算法获取到数组索引下标;

2.通过下标定位到数组对应的位置上

如果该位置啥也没有,返回null;

如果该位置上有链表或者红黑树,将node的k与链表的k进行equals比较如果有true,则返回该节点的。如果均为false,则返回null。

十六、什么是数据库回表?如何避免数据库回表

当mysql查询时,使用二级索引查到相应的叶子节点获取主键值,然后通过主键索引再查询到相应的数据行信息。其中,找到主键后,通过主键索引找到相应数据行的过程叫做回表。

如何避免回表的几种方式:

  1. 覆盖索引:将我们查询的字段设置为二级索引,这样我们通过二级索引就可以获得我们想要的值而不用回表。多字段的话需要遵循最佳左缀原则(参考第三条 复合索引失效场景);count(*)时,如果正好存在一个辅助索引,则会通过查询辅助索引统计数量,减少I/O
  2. 直接使用主键查询

十七、redis持久化方案有哪些?

  1. RDB:将redis在内存中的数据库记录定时dump到磁盘上的RDB持久化
  2. AOF:将Redis的操作日志以追加的方式写入文件

二者区别:

RDB持久化是指在指定的时间间隔内,将内存中的数据集快照写入磁盘,实际操作过程是fork()一个子进程(fork完以后,父进程和子进程有相同的数据段和代码段),先将数据集写入临时文件,写入成功后,再替换之前的文件,用二进制压缩存储。

AOF持久化以日志的形式记录服务器所处理的每一个写、删除操作,查询操作不会记录,以文本的方式记录,可以打开文件看到详细的操作记录。

RDB优缺点:

优点:

  1. 容灾备份非常方便,整个redis数据库只有一个文件,转移方便
  2. 性能比AOF好,因为他是有子进程fork进行持久化的,避免服务进程进行IO操作

缺点:

  1. 如果系统在持久化之前宕机,那么此前没来得及写入磁盘的数据都将会丢失
  2. 当数据集较大时,fork子进程时,耗时较大,可能会延迟服务反应时间

AOF优缺点:

优点:

  1. 这种机制可以每秒同步一次,甚至每次写入删除都可以同步一次,这样即便服务宕机,也不会造成数据丢失
  2. 该机制才用的是append模式,即便是在写入过程中宕机,也不会破坏日志中已存在的内容;如果是写入了一半儿就宕机了,在下一次启动之前,我们可以通过redis-check-aof工具解决数据一致性问题。
  3. 它包含了一个清晰的数据操作日志,也可以通过这种操作日志恢复数据

缺点:

  1. 数据量大于RDB,因为它包含了全部操作日志
  2. 每次都要做IO,效率慢于RDB

十八、redis主从复制集群是如何保障数据的一致性的呢?

98b3909dbf326ef930ba0bc387fcf93f.png

runID:每个redis实例生成的随机且唯一的ID,这里表示的是主节点的ID

offset:复制偏移量。

 主从一致性原理:

从节点第一次进行连接时,主节点会生成RDB文件进行全量复制,同时将新写入的命令存入缓冲区,发送给从节点,保障数据一致性。

多从节点的时候,可以选用级联的方式保障数据同步。

网络断开重连后,主从节点通过维护偏移量来同步写命令。

十九、redis是如何实现单线程的

        Redis客户端对服务端的每次调用都经历了发送命令、执行命令、返回结果三个过程。其中执行命阶段,所有命令都会进入一个队列中,然后逐个被执行。所以不会出现两条命令同时被执行,不会产生并发问题。

单线程指的是网络请求模块使用了一个线程(所以不需考虑并发安全性),即一个线程处理所有网络请求,其他模块仍用了多个线程。

二十、简述mybatis的一级缓存和二级缓存

一级缓存默认是开启的,缓存范围是以sqlsession会话为一次

二级缓存默认关闭,需要手动开启,它是以mapper的namespace为一个范围,即只要你通过这个namespace查的话,就会缓存,如果你在其他的namespace对这个表进行操作,再通过原来的namespace进行查找的话,查找的仍然是缓存的内容,不会更新;


二十一、ArrayList和LinkedList的区别

ArrayList:基于动态数组,连续内存存储,适合下标访问(随机访问),扩容机制:因为数组长度固定,超出长度存数据时需要新建数组(1.5倍扩容机制),然后将老数组的数据拷贝到新数组,如果不是尾部插入数据还会涉及到元素的移动(往后复制一份,插入新元素),使用尾插法并指定初始容量可以极大提升性能,甚至超过linkedList,因为linkedList需要创建大量node对象。

LinkedList:基于链表,可以存储在分散的内存中,适合做数据插入及删除操作,不适合查询:需要逐一遍历。遍历LinkedList尽量使用iterator,别用for循环,因为for循环体内通过get(i)取得某一元素时都需要对list重新进行遍历,性能消耗极大。另外不要试图使用indexOf等返回元素索引,并利用其进行遍历,使用indexOf对list进行了遍历,当结果为null时会遍历整个列表。

  • 1
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值