东方国信JAVA面经
文章目录
题目选自牛客面经!!! 内容来自个人整理!!!
1、mybatis使用流程
介绍
MyBatis的底层操作封装了JDBC的API,其工作原理和核心流程与JDBC的使用步骤一脉相承。
MyBatis的基本工作原理就是:先封装SQL,接着调用JDBC操作数据库,最后把数据库返回的表结果封装成Java类
JDBC对象
名称 | 描述 |
---|---|
DriverMananger | 用于注册数据库连接 |
Connection | 与数据库连接 |
Statement/PrepareStatement | 操作数据库SQL语句的对象 |
ResultSet | 结果集或一张虚拟表 |
Mybatis对象
名称 | 描述 |
---|---|
SqlSession | 包含了所有SQL语句,但是并不是执行者,类似Connection |
Executor | 根据SqlSession对象传来的参数动态生成SQL语句,同时负责查询缓存的维护 |
MappedStatement | 对映射SQL的封装,用于存储要映射SQL语句的ID、参数等信息 |
ResultHandler | 对返回结果进行处理,最终得到自己想要的数据格式或类型,可以自定义返回类型 |
tips: 在JDBC中,Connection不直接执行SQL方法,而是利用Statement或者PrepareStatement来执行方法。在使用JDBC建立了连接之后,可以使用Connection接口的createStatement()方法来获取Statement对象,也可以调用prepareStatement()方法获得PrepareStatement对象,通过executeUpdate()方法来执行SQL语句。而在MyBatis中,SqlSession对象包含了执行SQL语句的所有方法,但是它是委托Executor执行的。从某种意义上来看,MyBatis里面的SqlSession类似于JDBC中的Connection,他们都是委托给其他类去执行.
工作流程
以下内容均摘自:MyBatis中文官网 详细且易懂
流程描述
1、读取MyBatis配置文件。MyBatis-config.xml文件是全局配置文件,用于配置数据库连接信息
2、加载映射文件。映射文件即SQL文件,该文件配置了操作数据库的SQL语句,需要在全局配置文件加载,可以加载多个映射文件,每个映射文件对应一张表
3、构造会话工厂(会不会跟线程池一个目的),在全局配置文件中配置该信息
4、创建会话对象,由会话工厂创建SqlSession,该对象包含了所有SQL语句
5、执行器,操作数据库的底层接口,将会话对象传递的参数动态生成SQL语句,同时负责查询缓存的维护
6、MappedStatement对象,在执行器接口的执行方法中有一个MappedStatement类型的参数
7、入参数映射。输入参数类型可以是Map、List等集合类型,也可以是基本数据类型和POJO类型。输入参数映射过程类似于JDBC对preparedStatement对象设置参数的过程
8、输出结果映射。输出结果类型可以是Map、List等集合类型,也可以是基本数据类型和POJO类型。输出结果映射过程类似于JDBC对结果集的解析过程
2、JDBC使用流程
参考上面
3、Java垃圾回收器
介绍垃圾回收是什么 -> 垃圾回收器(一个专门负责垃圾回收的)—>既然是个机器,那么肯定会具有多样化,有哪些类型,以及特点->机器的性能,如何评价机器的好坏-> 如何运行的
概念:
垃圾回收(Garbage Collection, GC)是内存管理的核心组成部分,它负责回收不再使用的内存空间。在Java中,程序员不需要手动释放对象占用的内存,一旦对象不再被引用,GC就会在适当的时机回收他们所占用的内存。可以避免内存泄露和野指针。从而减轻了程序员的负担,也使得Java成为一个相对安全,易于开发的编程语言。
垃圾回收的基本步骤:
1、查找内存中不再被使用的对象(回收谁); 2、释放这些对象占用的内存(如何回收)。
垃圾回收器分类
分类 | 详细描述 | 理解 |
---|---|---|
按照功能模式分 | **并发式垃圾回收器:**与应用程序线程交替工作,以尽量减少应用程序的停顿时间 **独占式垃圾回收器:**stop-the-world,一旦运行,停止应用程序,直至过程完全结束。 | |
按照线程分 | **串行垃圾回收器:**同一时间段内只允许有一个CPU用于执行GC,要暂停工作内容,直至垃圾收集工作结束。 并行垃圾回收器:同一时间段内允许多个,但是也是"stop-the-world"。 | 这哥俩都是:清理垃圾ing,暂停营业。 |
按照碎片处理方式 | 压缩式垃圾回收器:在垃圾回收之后,对存活对象进行压缩整理,消除回收的碎片 非压缩式垃圾回收器:不执上述步骤。 | |
按照工作的内存空间 | 可以分为年轻代垃圾回收器和老年代垃圾回收器 |
GC的性能指标
- 吞吐量:运行应用程序的时间占总运行时间;
- 暂停时间:执行垃圾收集时,应用程序被暂停的时间
垃圾回收器的运行机制
1、Java对象的生命周期:
**状态:**创建、使用、不可达、回收、终结、死亡;
不可达:失去强引用的身份
回收:被GC带走了
终结:如果对象定义了finalize方法,会被在回收之前调用(这不就是保护罩吗,我还可以挣扎一下)
死亡:对象的内存被回收,对象完成其生命周期(家没了,就彻底没了)
大白话时间:
java之中被new的对象是一个强引用,是不回被垃圾回收的,因此会导致java内存泄露。
什么时候会失去强引用的身份:
1、设置为null(显示)
2、在一个方法内部有一个强引用,这个引用保存在栈中,而引用的对象保存在堆中。当这个方法运行完成后,就会退出方法栈,引用对象的引用数就是0,这个对象就可以被回收
内存泄露:已经分配的资源没有被正确地释放和回收,随着时间的推移,这些无法回收的内存资源持续积累,导致应用程序可能内存不足,甚至崩溃。
再写就多了 再去了解一下,四个引用的关系吧!
tips:不知不觉写了那么多,真复杂。
GC判断策略(回收谁)
应该就是判断一个对象是不是强引用,如果不是那就是可以回收,否则不能回收。
策略 | 描述 |
---|---|
引用计数算法 | 给对象加一个计数器,增加一个引用,计数器加1,引用失效,计数器减为0的对象可被回收。(如果两人循环引用,可以非常优秀,因此java虚拟机不使用引用计数算法,很好奇如何循环引用,比如一个对象的成员或者方法引用另一个对象,同样) |
可达性分析(JVM使用) | 我要开始贴图了(…) |
可达性分析算法
思路:
将一些称为GC Roots的对象,作为根节点,向下搜索,若某对象不可达,判定是可回收对象。
在可达性分析算法中,宣告一个对象的"死亡"至少要两次标记,因为finalize方法会暂时救它一命。(finalize翻译为最后确定,所以做重大决定之前,一定要再确定一下,否则就death了)
垃圾回收算法
经过上述已经确定了行动目标,那么如何消灭行动目标呢?因此如何有效回收不再使用的对象?
1、标记-清除
最基础的收集算法: Mark-Sweep算法,分为标记和清除阶段:
- 标记:在GC Roots遍历时,标记所有可回收对象
- 清除:遍历整个堆,清楚被标记的对象
算法缺点:
- 效率问题:标记和清除过程效率都不高;
- 空间问题:清除之后会产生大量不连续的碎片
2、复制
目的:为了解决效率问题
思路:将可用内存按容量大小划分为大小相等的两块,每次只使用其中的一块。当一块内 存使用完了,就将还存活着的对象复制到另一块上面,然后再把已使用过的内存空 间一次清理掉。这样使得每次都是对整个半区进行内存回收,内存分配时也就不用 考虑内存碎片等复杂情况。
缺点: 将内存缩小为了原来的一半。
tips:现代的商业虚拟机都采用这种收集算法来回收新生代,IBM公司的专门研究表明, 新生代中对象98%对象是“朝生夕死”的,所以不需要按照1:1的比例来划分内存空 间,而是将内存分为较大的Eden空间和两块较小的Survivor空间,每次使用Eden 和其中一块Survivor。HotSpot虚拟机中默认Eden和Survivor的大小比例是8: 1。
3、分代收集算法
一般是把Java堆分为新生代和老年代,这样就可以根据各个年代的特点采用最适当 的收集算法。
在新生代中,每次垃圾收集时都发现有大批对象死去,只有少量存活,那就选用复制算法。
在老年代中,因为对象存活率高、没有额外空间对它进行分配担保,就必须采用“标 记-清除”或“标记-整理”算法来进行回收。
4、标记-整理算法
复制收集算法在对象存活率较高时,就要进行较多的复制操作,效率就会变低。 根 据老年代的特点,提出了“标记-整理”算法。 标记过程仍然与”标记-清除“算法一样,但后续步骤不是直接对可回收对象进行清 理,而是让所有存活的对象都向一端移动,然后直接清理掉边界以外的内存。
tips: 肝不动了,大量芝士进入脑子,关于GC暂时就这样了。
参考
4、TCP和UDP的区别
两者都传输层的协议,可以从传输数据类型、是否建立连接、头部长度等区分
区别
- TCP面向连接,UDP面向无连接
- TCP面向字节流,UCP面向报文
- TCP提供安全可靠的传输服务、UDP尽最大努力传输
- TCP首部20字节,UDP首部8字节
- TCP连接是点对点的,UDP是一对多,多对多等通信
Tips: 发现找工作的时候会写熟悉TCP/IP协议,是需要在编程中应用吗,比如Java的套接字等
5、ArrayList和LinkedList区别
自我理解:
1、应该是和数据结构中的数组和链表相类似,数组是连续的内存空间,链表不要求是连续的内存空间
2、两者都是实现了Java中的接口List
查询资料整理
- ArrayList 底层是由数组实现的, LinkedLsit底层是由链表实现的; 所以ArrayList比LinkedList查询快
- Java的原生数组是不支持扩容的,但ArrayList支持动态扩容 (扩容问题可以单独拿来考察)
- ArrayList是线程不安全的
Tips: 这个问题问的很少,但是细节展开又是很多,所以可以整理一下List的实现类,然后对比分析.
6、你有使用过Kafka
如果是问我
嗯…,这是啥,不了解,不明白,不知道;不过好像是消息队列? 开始查一下资料
tips: 参考学习地址:kafka
7、主键索引和唯一索引的区别
唯一性要求:主键索引要求索引列的值在整个表中是唯一的,任何两行数据的主键值不能相同。而唯一索引也要求索引列的值是唯一的,但允许有部分行没有索引值(即允许为NULL)。
空值(NULL):主键索引不允许索引列的值为空(NULL),每一行都必须有一个主键值。而唯一索引允许索引列的值为空(NULL),允许有多行为空值。
表中数量:每个表只能有一个主键索引,用于唯一标识表中的每一行数据。而唯一索引可以有多个,可以在一个表中创建多个唯一索引。
自动增长:通常情况下,主键索引使用自动增长(AUTO_INCREMENT)来生成唯一的主键值。而唯一索引不一定需要使用自动增长。
在使用时,主键索引通常用于唯一标识表中的每一行数据,而唯一索引用于确保索引列的值是唯一的,但允许部分行为空值。你可以根据实际需求选择适当的索引类型。
表中数量:每个表只能有一个主键索引,用于唯一标识表中的每一行数据。而唯一索引可以有多个,可以在一个表中创建多个唯一索引。
**自动增长:**通常情况下,主键索引使用自动增长(AUTO_INCREMENT)来生成唯一的主键值。而唯一索引不一定需要使用自动增长。
在使用时,主键索引通常用于唯一标识表中的每一行数据,而唯一索引用于确保索引列的值是唯一的,但允许部分行为空值。你可以根据实际需求选择适当的索引类型。