阿里巴巴Java研发实习二面面经20190610

还是熟悉的自我介绍 。

1.数据库事务ACID

数据库ACID指的是数据库事务的原子性,一致性,隔离性和持久性。

原子性指的是一个事务作为数据库的执行单元,其中的操作要么全部成功,要么全部失败。

一致性指的是事务执行前后应该满足一致性条件,比如数据库中有个约束是 a + b = 10,a = 5,b = 5。当执行事务以后a变为7,那么根据一致性条件b就要变为3。

隔离性指的是在多个事务同时执行时数据库能够通过隔离级别来保证让各个事务对其他事务保持透明,也就是看起来像是同一时刻执行一个事务一样。

持久性指的是当一个事务对数据库数据产生修改并commit后,事务对于数据库的修改是持久的,不可逆的。

2.你刚刚提到了隔离级别,数据库都有那些隔离级别

隔离级别有四个,读未提交,读已提交,可重复读和串行化。他们分别可以解决脏读,不可重复读,幻读三个问题。

读未提交指的是两个事务同时进行,事务A能读到事务B处理过程中的任何数据,可能读到的是脏数据。是最低的隔离级别,效率最高。

读已提交指的是两个事务同时进行,事务A只能读到其他事务已经提交的数据,这样就能避免脏读的问题。

可重复读解决的是不可重复读问题,在读已提交隔离级别下,事务A内有两次读取,由于其他事务对数据的修改可能导致事务A的两次读取读到的值不同。可重复读就是能保证同一事务中读到的数据是保持一致的。

串行化是等级最高的隔离级别,在可重复读隔离级别下,在一个事务执行时,可能由于其他事务插入新记录,导致读取记录数量时得到的值不同,就像产生幻觉一样,这就是幻读问题。串行化隔离级别就是通过串行执行事务来解决这个问题,因此效率非常的低。

3.那你知道数据库中的隔离性是怎么做到的吗

我平时用的比较多的是MySQL数据库。

在MySQL数据库中,支持事务而且有比较好用的是InnoDB引擎。

在InnoDB引擎中主要是使用表锁,行锁,间隙锁和MVCC多版本并发控制来解决并发问题的。

表锁简单来说就是锁表,其他引擎比如说MyISAM也支持,并发效率比较低。InnoDB还支持基于索引的行锁,行锁的粒度要小于表锁,有更高的并发效率。并且由于MySQL默认的隔离级别是可重复读,这样会产生幻读问题,所以在InnoDB引擎中还加入了间隙锁。间隙锁是通过锁定记录行与记录行之间的间隙来避免幻影行的插入的。

除了使用锁,MySQL还通过MVCC实现事务的隔离性,MVCC多版本并发控制就是在每张表的末尾加入两个隐藏列,分别记录该行记录最新修改的版本号和删除时的版本号。然后给每个事务都指定一个版本号,事务在操作时指定读取到修改版本号在本事务 版本号之前,删除版本号在本事务版本号之后的数据。

总体来说,MVCC就是通过一个快照的形式加上版本号控制来做到隔离性的。

4.对数据库的索引了解吗?

了解,说到索引,MySQL是把索引存储在B+树上的。并且每个不同的存储引擎构建索引的方式也不同,比如MyISAM引擎是整体表分为两块存储,表的定义,表的所有数据。而InnoDB引擎则是分为三块,表的定义,表的数据和表的索引。他把索引和数据分开来存储,表的数据存储在一个大的聚簇索引上,这个索引是根据主键建立的。而其他的索引一般被称为二级索引,并且独立存储,二级索引里边存储的数据是主键的值。这样我们在使用InnoDB引擎通过索引检索数据时可能会有两次遍历树的操作,第一次通过二级索引找到对应的主键值,然后再通过主键在聚簇索引上查找数据。

5.为什么索引要存在B+树上呢?B+树比起B树和普通二叉树有什么有点。

首先B树是一种多路搜索树,它与二叉树最大的区别就是可以有多个分支,在存储数据时能让整棵树显得 矮胖。这样的结构非常适合现代计算机硬盘的存储结构。硬盘的存储单元是 页。B树的 矮胖 特性使得它在可以减少遍历树的次数,因为深度变小了嘛。这样就可以在读取更少页的情况下找到目标数据。

然后B+树是B树的改进型,主要区别就在于B+树在非叶子节点上不存储数据,只存储判断条件,所有的数据都存储在叶子节点上,并且叶子节点上的数据是有序的,再相互用指针连接起来,形成一个类似于链表的结构,这样就非常适合范围查找。而且InnoDB引擎的一大特性是 预读,就是通过预先读取数据来减少io次数,这个预读的某一种方式就是基于这个 链表 实现的。

B+树的非叶子节点上不存储数据,这个特性可以是非叶子节点的体积更小,在一个数据页中存储更多的非叶子节点,在遍历树时减少数据页的读取,整体上提高了效率。而且每次查询都需要到叶子节点上才能检索到数据,看似效率低下了,其实是让查询数据的操作变得稳定了,这样就有便于我们去给他们做优化。因此,使用B+树来做存储更适合。

6.接下来说说网络吧。三次握手和四次挥手知道吗?说一下吧

三次握手和四次挥手是TCP建立连接和释放连接时的流程。

三次握手是建立连接,首先第一次握手是客户端发送一个报文到服务端,该报文SYN位置为1,随机产生seq序号。第二次握手是服务端对客户端的回应,该报文是把SYN置为1,ACK置为1,ack需要位上个报文的seq序号+1,并且自己产生一个seq序号。第三次握手是客户端对服务端的回应,该报文把ACK置为1,ack序号为上个报文seq序号+1,seq序号为上一个客户端报文的seq序号+1。至此完成三次握手。

四次挥手是释放tcp连接的流程,其中分别用两次挥手来释放客户端和服务端的连接。前两次挥手是释放客户端的连接,两次挥手结束后,客户端处于一个timewait状态,因为这时客户端和服务端断开连接,不再向服务端发送信息,但是服务端的连接并没有释放,服务端还可能向客户端发送消息。之后再通过俩次挥手释放服务端的连接,至此连接全部断开。

7.如果在第三次或者第四次挥手时断网了会怎么样

(ps:这个地方我没有仔细去看,就根据等待时间这一块自己推断的说了一下,应该说的不太对。)

8.TCP和UDP有什么区别

TCP和UDP都是网络层的协议,TCP是面向连接的可靠协议,UDP是面向报文的不可靠协议。

使用TCP时,首先要通过三次握手建立一个逻辑管道,数据在这个管道上流通。UDP在使用时直接发送数据报就行。

TCP的报文头是20字节,因为要实现安全性。而UDP只有8个字节,目的端口,源端口,长度和校验,比较简单。

TCP一般会比UDP慢一些。

TCP和UDP的应用场景不同,TCP适合数据量相对较小,对安全需求高的场景,比如HTTP请求这样的。而UDP适合大数据量,对安全性要求不高的场合,比如说直播,网络视频这样。

9.你刚刚说TCP是安全的,那么它怎么实现安全性

TCP主要通过四点实现安全性。

第一是TCP报文是有序号的,这样接收方就能知道整个数据是不是完整的抵达。

第二是TCP报文在接收后需要进行确认,这个操作能让发送方知道数据是不是成功抵达了。

第三点是拥塞控制,能够让TCP的传输速度保持在一个安全的状态。

前三点时能保证TCP在传输过程中的安全性。

第四点是TCP报文头中有一个校验和字段,该字段可以检验TCP数据报是否完整,是否被修改过,这就能保证TCP报文数据的安全性了。

通过这四点的处理,TCP能实现安全性。

10.来说说数据结构吧,比较一下快排和堆排

快速排序是一种不稳定排序,平均时间复杂度是0(nlogn),最坏时间复杂度是0(n^2),空间复杂度是0(nlogn)。快排的核心思想是在一次排序的中寻找一个轴,然后把小于轴点数值的数和大于轴点数值的数放到轴的两边,然后在通过给左右两边的数据集选轴进行排序的过程,用一种分治的思想解决问题。

堆排序也是一种不稳定排序,平均和最坏时间复杂读都是0(nlogn),空间复杂度是0(1)。堆排是把整个数据集看作一个大顶堆或小顶堆,通过左右孩子节点比较,父子节点比较的方式把最大或最小的数据推到堆顶,然后把堆顶数据和数据集末尾数据交换,以此完成一次排序。

堆排序比起快排要稍好一点,但写起来比较复杂。在JDK集合包中的sort()方法使用的是优化的快排和优化的归并排序。因此我觉得平时使用的话,用快排比较好。

11.了解图论吗?说一下最短路径算法

我平时做题使用的最短路径算法是SPFA算法,该算法比起Dijkstra算法最大的好处就是允许节点路径为负数。它的思想和其他最短路径算法的思想一样,都是通过一个数组存储起点到目标节点的路径,然后进行路径松弛操作。

SPFA进行松弛操作的方法是通过一个队列,放入相互连接的节点,然后让这些节点出队,每次出队判断一下是否能通过这个节点来找到更短的路径,知道队列中没有节点。此时数组中存放的就是起点到各个目标节点最短的路径。

12.来聊一下你的项目吧,简单说一下。

是一个c2c项目。。。。。。。。。。。。

主要是用了Spring技术。

13.你觉得Spring给你的项目带来了什么好处,或者说你为什么要用Spring

首先Spring是个侵入性非常小的框架,使用Spring不会对业务代码有很大的改动,从之前的Spring framework到现在热门的SpringBoot,使用Spring的门槛也是越来越低。

还有就是Spring带来了IOC,AOP的功能。IOC给我的项目进行了一次彻底的解耦,让我对项目中的每个模块,每个类都能更好,更系统的去管理它。

AOP则是提供了面向切点编程,让项目的业务代码和系统服务代码得以分离,在解耦的同时提高了代码可读性。

还有Spring的一些生态特别强大,它海纳百川的思想让我的项目在拓展性方面得以提升,不管是之后用到了什么框架,Spring都能很好的集成,而且Spring还提供了想SpringMVC这样的其他功能框架,整体使用起来非常的方便。

14.Spring的源码有看过吗?

看过。

15.说一下SpringAOP的底层原理吧

AOP是一种面向切面编程的思想。Spring实现AOP是通过设计模式中的代理模式实现的,通过动态代理的方式在运行时生成代理类,然后在代理类内部由组合和方法回调的方法去实现功能,并且在把切面织入到需要加强的代理方法中去。

Spring使用的动态代理技术主要是JDK代理和CGLIB代理,JDK动态代理是反射包中的一个功能,可以产生基于接口的代理类。CGLIB则是基于继承的思想,操作Java字节码产生代理类,并在代理类中回调原生类的方法。

16.你的项目有对用户登录这一块做状态保持或者安全性吗?比如用Session这样。

我之前用Session做过用户状态保存,但是我有个学长让我使用token去做这个,我也是通过查阅资料后进行了改进,现在是使用JWT的token去做用户状态保存和安全性的。

之所以换成token,是因为Session的产生和操作都是web服务器帮我做的,我对它的控制能力很有限,无法做更多的扩展,而且Session是绑定服务器的,将来如果使用分布式服务器的话会出现问题。所以我换成token,并配合自己写的缓存来保证对token的控制能力。

17.自己写的缓存?你有了解过其他的缓存吗?

有了解,我在项目也是使用了Redis做缓存服务,现在再看《Redis设计与实现》这本书进一步去学习。

18.你自己写的缓存可以讲讲吗?

首先,缓存肯定要保证线程安全的,我使用的ConcurrentHashMap把用户ID和token进行一个映射保存,ConcurrentHashMap具有线程安全性,并且效率也比HashTable好。然后就是缓存一般都会有过期时间这个功能,我是使用的ScheduledTreadPoolExecutor实现的,这个线程池中可以提交一些定时的任务,我用它来把过期的数据从ConcurrentHashMap中的剔除。

19.据我所知,Java中还有其他方法可以实现定时操作,你为什么就用线程池呢?

之前我用的是Timer类去做定时,然后就是前段时间正好在读《Java并发编程的艺术》,也深入了解了线程池。觉得线程池能实现比Timer更多的功能,并且能更好的定制。因此选择了线程池,其他的解决方案我就不太了解了。。。。

20.如果你要学习一项技术,就拿你现在在学的Redis来说,你会怎么样去学习它

这个要根据学习的东西来说,如果这门技术是项目中的要求,需要我用最快的时间弄好他。我会先通过看一些技术博客和视频快速上手,先在测试环境把这一块做出来,让他能勾跑起来。然后通过阅读经典的技术书籍来加深学习知识点。

如果这门技术已经非常的成熟了,是一种沉淀下来的思想,比如说多线程这样的技术。我会通过看一些经典的书籍去理解它的底层,深入的学习。

21.项目中有没有遇到一些难点,让你记忆犹新的

有一些,这里我讲了项目中的一个请求转发问题。

22.有没有想要问我的

我:请您对我这次面试做个点评吧,指出我的不足

面试官:我觉得你的基础还是ok的,在学校也能自己做项目,项目这一块也是ok的,整体这次面试也是ok的。

 

总结

这是我经历过最长时间的面试,没有手撕代码,足足和面试官唠了60多分钟。最后面试官对我也是比较认可,不得不说阿里巴巴的面试真的是面面俱到,问的又广又深。这次面试应该是通过了,希望之后的面试也能顺顺利利的。

 

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值