首页 > Java基础之Hibernate面试题
头像
Java程序员小云
发布于 2022-01-23 19:56
+ 关注

Java基础之Hibernate面试题


给大家介绍了流行了框架中的常见面试题,主要包括spring/spring mvc以及spring boot和spring cloud的相关面试题。
今天继续为大家介绍java后端开发常见的面试题。首先给大家介绍的就是Hibernate的常见面试题:

一、Hibernate

1、为什么要使用 hibernate?

hibernate 是对 jdbc 的封装,大大简化了数据访问层的繁琐的重复性代码。
hibernate 是一个优秀的 ORM 实现,很多程度上简化了 DAO 层的编码功能。
可以很方便的进行数据库的移植工作
提供了缓存机制,是程序执行更改的高效

2、什么是 ORM 框架?

ORM(Object Relation Mapping)对象关系映射,是把数据库中的关系数据映射成为程序中的对象。
使用 ORM 的优点:提高了开发效率降低了开发成本、开发更简单更对象化、可移植更强。

3、hibernate 中如何在控制台查看打印的 SQL 语句?

在 Config 里面把 hibernate. show_SQL 设置为 true 就可以。但不建议开启,开启之后会降低程序的运行效率。

4、hibernate 有几种查询方式?

三种:hql、原生 SQL、条件查询 Criteria。

5、hibernate 实体类可以被定义为 final 吗?

实体类可以定义为 final 类,但这样的话就不能使用 hibernate 代理模式下的延迟关联提供性能了,所以不建议定义实体类为 final。

6、在 hibernate 中使用 Integer 和 int 做映射有什么区别?

Integer 类型为对象,它的值允许为 null,而 int 属于基础数据类型,值不能为 null。

7、 hibernate 是如何工作的?

• 读取并解析配置文件。
• 读取并解析映射文件,创建 SessionFactory。
• 打开 Session。
• 创建事务。
• 进行持久化操作。
• 提交事务。
• 关闭 Session。
• 关闭 SessionFactory。

8、get()和 load()的区别?

• 数据查询时,没有 OID 指定的对象,get() 返回 null;load() 返回一个代理对象。
• load()支持延迟加载;get() 不支持延迟加载。

9、说一下 hibernate 的缓存机制?

hibernate 常用的缓存有一级缓存和二级缓存:
一级缓存:也叫 Session 缓存,只在 Session 作用范围内有效,不需要用户干涉,由 hibernate 自身维护,可以通过:evict(object)清除 object 的缓存;clear()清除一级缓存中的所有缓存;flush()刷出缓存;
二级缓存:应用级别的缓存,在所有 Session 中都有效,支持配置第三方的缓存,如:EhCache。

10、hibernate 对象有哪些状态?

临时/瞬时状态:直接 new 出来的对象,该对象还没被持久化(没保存在数据库中),不受 Session 管理。
持久化状态:当调用 Session 的 save/saveOrupdate/get/load/list 等方法的时候,对象就是持久化状态。
游离状态:Session 关闭之后对象就是游离状态。

11、在 hibernate 中 getCurrentSession 和 openSession 的区别是什么?

• getCurrentSession 会绑定当前线程,而 openSession 则不会。
• getCurrentSession 事务是 Spring 控制的,并且不需要手动关闭,而 openSession 需要我们自己手动开启和提交事务。

12、hibernate 实体类必须要有无参构造函数吗?为什么?

hibernate 中每个实体类必须提供一个无参构造函数,因为 hibernate 框架要使用 reflection api,通过调用 ClassnewInstance() 来创建实体类的实例,如果没有无参的构造函数就会抛出异常。

二、MyBatis

1、MyBatis 中 #{}和 ${}的区别是什么?

#{}是预编译处理,${}是字符替换。 在使用 #{}时,MyBatis 会将 SQL 中的 #{}替换成“?”,配合 PreparedStatement 的 set 方法赋值,这样可以有效的防止 SQL 注入,保证程序的运行安全。

2、MyBatis 有几种分页方式?

分页方式:逻辑分页和物理分页。
逻辑分页: 使用 MyBatis 自带的 RowBounds 进行分页,它是一次性查询很多数据,然后在数据中再进行检索。
物理分页: 自己手写 SQL 分页或使用分页插件 PageHelper,去数据库查询指定条数的分页数据的形式。

3、RowBounds 是一次性查询全部结果吗?为什么?

RowBounds 表面是在“所有”数据中检索数据,其实并非是一次性查询出所有数据,因为 MyBatis 是对 jdbc 的封装,在 jdbc 驱动中有一个 Fetch Size 的配置,它规定了每次最多从数据库查询多少条数据,假如你要查询更多数据,它会在你执行 next()的时候,去查询更多的数据。就好比你去自动取款机取 10000 元,但取款机每次最多能取 2500 元,所以你要取 4 次才能把钱取完。只是对于 jdbc 来说,当你调用 next()的时候会自动帮你完成查询工作。这样做的好处可以有效的防止内存溢出。

4、MyBatis 逻辑分页和物理分页的区别是什么?

逻辑分页是一次性查询很多数据,然后再在结果中检索分页的数据。这样做弊端是需要消耗大量的内存、有内存溢出的风险、对数据库压力较大。
物理分页是从数据库查询指定条数的数据,弥补了一次性全部查出的所有数据的种种缺点,比如需要大量的内存,对数据库查询压力较大等问题。

5、MyBatis 是否支持延迟加载?延迟加载的原理是什么?

MyBatis 支持延迟加载,设置 lazyLoadingEnabled=true 即可。
延迟加载的原理的是调用的时候触发加载,而不是在初始化的时候就加载信息。比如调用 a. getB(). getName(),这个时候发现 a. getB() 的值为 null,此时会单独触发事先保存好的关联 B 对象的 SQL,先查询出来 B,然后再调用 a. setB(b),而这时候再调用 a. getB(). getName() 就有值了,这就是延迟加载的基本原理。

6、说一下 MyBatis 的一级缓存和二级缓存?

一级缓存:基于 PerpetualCache 的 HashMap 本地缓存,它的声明周期是和 SQLSession 一致的,有多个 SQLSession 或者分布式的环境中数据库操作,可能会出现脏数据。当 Session flush 或 close 之后,该 Session 中的所有 Cache 就将清空,默认一级缓存是开启的。
二级缓存:也是基于 PerpetualCache 的 HashMap 本地缓存,不同在于其存储作用域为 Mapper 级别的,如果多个SQLSession之间需要共享缓存,则需要使用到二级缓存,并且二级缓存可自定义存储源,如 Ehcache。默认不打开二级缓存,要开启二级缓存,使用二级缓存属性类需要实现 Serializable 序列化接口(可用来保存对象的状态)。
开启二级缓存数据查询流程:二级缓存 -> 一级缓存 -> 数据库。
缓存更新机制:当某一个作用域(一级缓存 Session/二级缓存 Mapper)进行了C/U/D 操作后,默认该作用域下所有 select 中的缓存将被 clear。

7、 MyBatis 和 hibernate 的区别有哪些?

灵活性:MyBatis 更加灵活,自己可以写 SQL 语句,使用起来比较方便。
可移植性:MyBatis 有很多自己写的 SQL,因为每个数据库的 SQL 可以不相同,所以可移植性比较差。
学习和使用门槛:MyBatis 入门比较简单,使用门槛也更低。
二级缓存:hibernate 拥有更好的二级缓存,它的二级缓存可以自行更换为第三方的二级缓存。

8、MyBatis 有哪些执行器(Executor)?

MyBatis 有三种基本的Executor执行器
SimpleExecutor:每执行一次 update 或 select 就开启一个 Statement 对象,用完立刻关闭 Statement 对象;
ReuseExecutor:执行 update 或 select,以 SQL 作为 key 查找 Statement 对象,存在就使用,不存在就创建,用完后不关闭 Statement 对象,而是放置于 Map 内供下一次使用。简言之,就是重复使用 Statement 对象;
BatchExecutor:执行 update(没有 select,jdbc 批处理不支持 select),将所有 SQL 都添加到批处理中(addBatch()),等待统一执行(executeBatch()),它缓存了多个 Statement 对象,每个 Statement 对象都是 addBatch()完毕后,等待逐一执行 executeBatch()批处理,与 jdbc 批处理相同。

9、MyBatis 分页插件的实现原理是什么?

分页插件的基本原理是使用 MyBatis 提供的插件接口,实现自定义插件,在插件的拦截方法内拦截待执行的 SQL,然后重写 SQL,根据 dialect 方言,添加对应的物理分页语句和物理分页参数。

10、MyBatis 如何编写一个自定义插件?

自定义插件实现原理:
MyBatis 自定义插件针对 MyBatis 四大对象(Executor、StatementHandler、ParameterHandler、ResultSetHandler)进行拦截:
Executor:拦截内部执行器,它负责调用 StatementHandler 操作数据库,并把结果集通过 ResultSetHandler 进行自动映射,另外它还处理了二级缓存的操作;
StatementHandler:拦截 SQL 语法构建的处理,它是 MyBatis 直接和数据库执行 SQL 脚本的对象,另外它也实现了 MyBatis 的一级缓存;
ParameterHandler:拦截参数的处理;
ResultSetHandler:拦截结果集的处理。

自定义插件实现关键
MyBatis 插件要实现 Interceptor 接口,接口包含的方法,如下:

import java.util.Properties; public interface Interpector<Invocation> {     Object intercept(Invocation invocation) throws Throwable;     Object plugin(Object target);     void setProperties(Properties properties); }

setProperties 方法是在 MyBatis 进行配置插件的时候可以配置自定义相关属性,即:接口实现对象的参数配置;

plugin 方法是插件用于封装目标对象的,通过该方法我们可以返回目标对象本身,也可以返回一个它的代理,可以决定是否要进行拦截进而决定要返回一个什么样的目标对象,官方提供了示例:return Plugin. wrap(target, this);

intercept 方法就是要进行拦截的时候要执行的方法。

自定义插件实现示例

@Intercepts({@Signature(type = Executor. class, method = "query", args = {MappedStatement. class, Object. class, RowBounds. class, ResultHandler. class})}) public class TestInterceptor implements Interceptor { public Object intercept(Invocation invocation) throws Throwable { Object target = invocation. getTarget(); //被代理对象  Method method = invocation. getMethod(); //代理方法  Object[] args = invocation. getArgs(); //方法参数  // do something . . . . . .  方法拦截前执行代码块  Object result = invocation. proceed(); // do something . . . . . . . 方法拦截后执行代码块  return result; } public Object plugin(Object target) { return Plugin. wrap(target, this); } }

三、RabbitMQ

1、RabbitMQ 的使用场景有哪些?

抢购活动,削峰填谷,防止系统崩塌。
延迟信息处理,比如 10 分钟之后给下单未付款的用户发送邮件提醒。
解耦系统,对于新增的功能可以单独写模块扩展,比如用户确认评价之后,新增了给用户返积分的功能,这个时候不用在业务代码里添加新增积分的功能,只需要把新增积分的接口订阅确认评价的消息队列即可,后面再添加任何功能只需要订阅对应的消息队列即可。

2、RabbitMQ 有哪些重要的角色?

RabbitMQ 中重要的角色有:生产者、消费者和代理:
生产者:消息的创建者,负责创建和推送数据到消息服务器;
消费者:消息的接收方,用于处理数据和确认消息;
代理:就是 RabbitMQ 本身,用于扮演“快递”的角色,本身不生产消息,只是扮演“快递”的角色。

3、RabbitMQ 有哪些重要的组件?

ConnectionFactory(连接管理器):应用程序与Rabbit之间建立连接的管理器,程序代码中使用。
Channel(信道):消息推送使用的通道。
Exchange(交换器:用于接受、分配消息。
Queue(队列):用于存储生产者的消息。
RoutingKey(路由键):用于把生成者的数据分配到交换器上。
BindingKey(绑定键):用于把交换器的消息绑定到队列上。

4、RabbitMQ 中 vhost 的作用是什么?

vhost:每个 RabbitMQ 都能创建很多 vhost,我们称之为虚拟主机,每个虚拟主机其实都是 mini 版的RabbitMQ,它拥有自己的队列,交换器和绑定,拥有自己的权限机制。

5、RabbitMQ 的消息是怎么发送的?

首先客户端必须连接到 RabbitMQ 服务器才能发布和消费消息,客户端和 rabbit server 之间会创建一个 tcp 连接,一旦 tcp 打开并通过了认证(认证就是你发送给 rabbit 服务器的用户名和密码),你的客户端和 RabbitMQ 就创建了一条 amqp 信道(channel),信道是创建在“真实” tcp 上的虚拟连接,amqp 命令都是通过信道发送出去的,每个信道都会有一个唯一的 id,不论是发布消息,订阅队列都是通过这个信道完成的。

6、RabbitMQ 怎么保证消息的稳定性?

• 提供了事务的功能。
• 通过将 channel 设置为 confirm(确认)模式。

7、RabbitMQ 怎么避免消息丢失?

• 把消息持久化磁盘,保证服务器重启消息不丢失。
• 每个集群中至少有一个物理磁盘,保证消息落入磁盘。

8、要保证消息持久化成功的条件有哪些?

以下四个条件都满足才能保证消息持久化成功。
• 声明队列必须设置持久化 durable 设置为 true.
• 消息推送投递模式必须设置持久化,deliveryMode 设置为 2(持久)。
• 消息已经到达持久化交换器。
• 消息已经到达持久化队列。

9、 RabbitMQ 持久化有什么缺点?

持久化的缺地就是降低了服务器的吞吐量,因为使用的是磁盘而非内存存储,从而降低了吞吐量。可尽量***d 硬盘来缓解吞吐量的问题。

10、RabbitMQ 有几种广播类型?

direct(默认方式):最基础最简单的模式,发送方把消息发送给订阅方,如果有多个订阅者,默认采取轮询的方式进行消息发送。
headers:与 direct 类似,只是性能很差,此类型几乎用不到。
fanout:分发模式,把消费分发给所有订阅者。
topic:匹配订阅模式,使用正则匹配到消息队列,能匹配到的都能接收到。

11、RabbitMQ 怎么实现延迟消息队列?

延迟队列的实现有两种方式:
• 通过消息过期后进入死信交换器,再由交换器转发到延迟消费队列,实现延迟功能;
• 使用 RabbitMQ-delayed-message-exchange 插件实现延迟功能。

12、 RabbitMQ 集群有什么用?

集群主要有以下两个用途:
高可用:某个服务器出现问题,整个 RabbitMQ 还可以继续使用;
高容量:集群可以承载更多的消息量。

13、RabbitMQ 节点的类型有哪些?

磁盘节点:消息会存储到磁盘。
内存节点:消息都存储在内存中,重启服务器消息丢失,性能高于磁盘类型。

14、RabbitMQ 集群搭建需要注意哪些问题?

• 各节点之间使用“–link”连接,此属性不能忽略。
• 各节点使用的 erlang cookie 值必须相同,此值相当于“秘钥”的功能,用于各节点的认证。
• 整个集群中必须包含一个磁盘节点。

15、RabbitMQ 每个节点是其他节点的完整拷贝吗?为什么?

不是,原因有以下两个:
存储空间的考虑:如果每个节点都拥有所有队列的完全拷贝,这样新增节点不但没有新增存储空间,反而增加了更多的冗余数据;
性能的考虑:如果每条消息都需要完整拷贝到每一个集群节点,那新增节点并没有提升处理消息的能力,最多是保持和单节点相同的性能甚至是更糟。

16、RabbitMQ 集群中唯一一个磁盘节点崩溃了会发生什么情况?

如果唯一磁盘的磁盘节点崩溃了,不能进行以下操作:
不能创建队列
不能创建交换器
不能创建绑定
不能添加用户
不能更改权限
不能添加和删除集群节点
唯一磁盘节点崩溃了,集群是可以保持运行的,但你不能更改任何东西。

17、RabbitMQ 对集群节点停止顺序有要求吗?

RabbitMQ 对集群的停止的顺序是有要求的,应该先关闭内存节点,最后再关闭磁盘节点。如果顺序恰好相反的话,可能会造成消息的丢失。

总结

给大家介绍了流行了框架中的常见面试题,主要包括spring/spring mvc以及spring boot和spring cloud的相关面试题。本文继续为大家介绍了java后端开发常见的面试题。主要包括Hibernate、Mybatis、Rabbit MQ的相关常见的面试。希望大家在理解的基础上好好掌握,这是java的基础,也是核心,只有这些基础知识掌握扎实,我们才会更好的将这些应用在实际的开发过程中。总之,无论是面试还是初学者,本文对java方向的同行们多多少说会有帮助,希望大家认真学习,努力工作,活到老,学到老,不断提高自己的技能水平。同时也希望正在找工作的小伙伴们都能找到一份满意的工作!!!!

全部评论

(0) 回帖
加载中...
话题 回帖