Hibernate 面试大全
1. Hibernate使用过程
1. 读取配置文件Configuration类
2. 创建SessionFactory对象
3. 创建Session对象
4. 开启事务
5. 进行数据库操作
6. 提交事务
7. 关闭Session
8. 关闭SesstionFactory
2. Hibernate是如何延迟加载(懒加载)?
Hibernate在查询数据的时候,并没有将数据加载到内存中。只有真正操作数据的时候对象才会存在于内存当中,这样实现了懒加载。节省了服务器的内存开销,从而提高了服务器的性能
3. Hibernate中怎样实现类之间的关系?(如:一对多、多对多的关系)
在配置文件中使用 many-to-one one-to-many many-to-many
4. hibernate的三种状态之间如何转换
-
临时/瞬时状态 transient
当我们直接new出来的对象就是临时/瞬时状态的
该对象还没有被持久化【没有保存在数据库中】
不受Session的管理 -
持久态
当保存在数据库中的对象就是持久化状态了
当调用session的save/saveOrUpdate/get/load/list等方法的时候,对象就是持久化状态
在数据库有对应的数据
受Session的管理
当对对象属性进行更改的时候,会反映到数据库中 -
游离态
当Session关闭了以后,持久化的对象就变成了游离状态了 或者使用delete方法删除了这个数据
不处于session的管理
数据库中有对应的记录
三态
1.瞬态:通过Java关键字new的实体类对象,不和Session实例关联并且在数据库中没有和瞬态对象关联的记录,此时的对象还没有纳入Hibernate的缓存管理中。
2.持久态: 已经被保存进数据库的实体对象,还存于Hibernate的缓存管理之中。
3.游离态(脱管态):持久态对象脱离了Hibernate的缓存管理后就会变成游离态,游离态对象与瞬态对象的最大区别在于,游离态对象在数据库中可能存在一条与之对应的记录,而瞬态对象则不会在数据库中存在与之对应的记录,简而言之就是游离态对象比瞬态对象多了一个ID属性。
5. 比较hibernate的三种检索策略优缺点
1立即检索;
优点: 对应用程序完全透明,不管对象处于持久化状态,还是游离状态,应用程序都可以方便的从一个对象导航到与它关联的对象;
缺点: 1.select语句太多;2.可能会加载应用程序不需要访问的对象白白浪费许多内存空间;
2延迟检索:
优点: 由应用程序决定需要加载哪些对象,可以避免可执行多余的select语句,以及避免加载应用程序不需要访问的对象。因此能提高检索性能,并且能节省内存空间;
缺点: 应用程序如果希望访问游离状态代理类实例,必须保证他在持久化状态时已经被初始化;
3 迫切左外连接检索
优点: 1对应用程序完全透明,不管对象处于持久化状态,还是游离状态,应用程序都可以方便地冲一个对象导航到与它关联的对象。2使用了外连接,select语句数目少;
缺点: 1 可能会加载应用程序不需要访问的对象,白白浪费许多内存空间;2复杂的数据库表连接也会影响检索性能;
6. hibernate都支持哪些缓存策略
1.放入二级缓存的对象,只读(Read-only);
2.非严格的读写(Nonstrict read/write)
3.读写; 放入二级缓存的对象可以读、写(Read/write);
4.基于事务的策略(Transactional)
7. hibernate里面的sorted collection 和ordered collection有什么区别
sorted collection 是在内存中进行排序
ordered collection 是在数据库中通过order by进行排序
8. Hibernate的缓存机制
-
一级缓存
也叫做session的缓存,它可以在session范围内减少数据库的访问次数! 只在session范围有效! Session关闭,一级缓存失效
只要是持久化对象状态的,都受Session管理,也就是说,都会在Session缓存中!
Session的缓存由hibernate维护,用户不能操作缓存内容; 如果想操作缓存内容,必须通过hibernate提供的evit()/clear()方法操作。 -
二级缓存
二级缓存是基于应用程序的缓存,所有的Session都可以使用
Hibernate提供的二级缓存有默认的实现,且是一种可插配的缓存框架!如果用户想用二级缓存,只需要在hibernate.cfg.xml中配置即可; 不想用,直接移除,不影响代码。
如果用户觉得hibernate提供的框架框架不好用,自己可以换其他的缓存框架或自己实现缓存框架都可以。
Hibernate二级缓存:存储的是常用的类
一级缓存,session对象的生命周期与一个数据库事务或应用事务相对应。因此session对象的缓存是事务范围的缓存。在一级缓存中,持久化类的实例都有一个唯一的OID
二级缓存,SessionFactory缓存。
由于SessionFactory对象的生命周期和应用程序的整个过程对应,因此Hibernate二级缓存是进程范围或者集群范围的缓存,有可能出现并发问题,因此需要采用适当的并发访问策略,该策略为被缓存的数据提供了事务隔离级别。第二级缓存是可选的,是一个可配置的插件,在默认情况下,SessionFactory不会启用这个插件。
8.1 什么样的数据适合存放到第二级缓存中?
1 很少被修改的数据
2 不是很重要的数据,允许出现偶尔并发的数据
3 不会被并发访问的数据
4 常量数据
不适合存放到第二级缓存的数据?
1.经常被修改的数据
2.绝对不允许出现并发访问的数据,如财务数据,绝对不允许出现并发
3.与其他应用共享的数据。
9. Hibernate的查询方式有几种
- OID查询 根据对象的主键
eg: Customer customer = session.load(Customer.class,1l);
eg: Customer customer = session.get(Customer.class,1l); - 对象导航查询(objectcomposition):对象导航检索:Hibernate根据一个已经查询到的对象,获得其关联的对象的一种查询方式。
LinkMan linkMan = session.get(LinkMan.class,1l);
Customer customer = linkMan.getCustomer();
Customer customer = session.get(Customer.class,2l);
Set<LinkMan> linkMans = customer.getLinkMans();
- HQL查询
1、 属性查询
2、 参数查询、命名参数查询
3、 关联查询
4、 分页查询
5、 统计函数 - QBC query by criteria
- SQLQuery本地SQL查询
10. 如何优化Hibernate?
? 数据库设计调整
? HQL优化
? API的正确使用(如根据不同的业务类型选用不同的集合及查询API)
? 主配置参数(日志,查询缓存,fetch_size, batch_size等)
? 映射文件优化(ID生成策略,二级缓存,延迟加载,关联优化)
? 一级缓存的管理
? 针对二级缓存,还有许多特有的策略
11. 谈谈Hibernate中inverse的作用
inverse属性默认是false,就是说关系的两端都来维护关系。
1. 比如Student和Teacher是多对多关系,用一个中间表TeacherStudent维护。Gp)
2. 如果Student这边inverse=”true”, 那么关系由另一端Teacher维护,就是说当插入Student时,不会操作TeacherStudent表(中间表)。只有Teacher插入或删除时才会触发对中间表的操作。所以两边都inverse=”true”是不对的,会导致任何操作都不触发对中间表的影响;当两边都inverse=”false”或默认时,会导致在中间表中插入两次关系。
如果表之间的关联关系是“一对多”的话,那么inverse只能在“一”的一方来配置!
12. JDBC hibernate 和 ibatis 的区别
-
JDBC
手写sql
delete、insert、update要将对象的值一个一个取出传到sql中,不能直接传入一个对象。
select:返回的是一个resultset,要从ResultSet中一行一行、一个字段一个字段的取出,然后封装到一个对象中,不直接返回一个对象。 -
hibernate 全自动
不写sql,自动封装
delete、insert、update可以传入对象
select直接返回对象 -
ibatis 半自动
手动sql
delete、insert、update可以传入对象
select直接返回对象
13. 在数据库中条件查询速度很慢的时候,如何优化?
- 建立索引
- 减少表之间的关联
- 优化sql,尽量让sql很快定位数据,不要让sql做全表查询,应该走索引,把数据量大的表排在前面
14. 什么是SessionFactory,她是线程安全么。 Session呢
-
SessionFactory是Hibernate中的数据库存储的一个概念,他是线程安全的, 可以被多个线程并发访问。SessionFactory一般只会在启动的时候构建。
SessionFactory接口负责Hibernate的初始化和建立Session对象。
它在Hibernate中起到一个缓冲区作用. Hibernate可以将自动生成的SQL语句、映射数据以及某些可重复利用的数据放在这个缓冲区中。同时它还保存了对数据库配置的所有映射关系,维护了当前的二级缓存。
SessionFactory是一个线程安全的对象,所有由该工厂生产的Session都共享工厂中维护的数据 .
- Session是一个轻量级非线程安全的对象(线程间不能共享session),它表示与数据库进行交互的一个工作单元。
15. get和load区别
-
get() 立即加载
get()方法返回的是一个实例对象。如果不存在该数据,返回null -
load() 延迟加载
load() 首先在一级缓存中查找, 如果没有查找到返回一个代理对象。 然后在二级缓存,数据库中查找。如果不存在这个数据。就会报错
16. merge的含义
-
merge的出现的原因
在一个session中存在两个不同的实体却有着相同的身份标签(主键)是会报错的,这时为了避免这种错误就可以使用Hibernate提供的merge()方法。 -
merge()方法的使用特性
1.new一个对象并设置ID时,这个对象会被当作游离态处理,在使用merge时,如果在数据库中不能能找到这条记录,则使用insert将数据插入;如果在数据库中找到这条记录,则使用update将数据更新。2.new一个对象没有设置ID时,这个对象会被当作瞬态处理,在使用merge时会根据实体类的主键生成策略保存这条数据。
3.使用merge存储到数据库的对象,其本身不会转变为持久态对象。
17. persist和save的区别
1.persist不保证立即执行,要等到flush
2.save()立即执行,将瞬态转换为持久化
3.persist()没有返回值
4.save()返回持久化标识符(对象的主键)
18. 主键生成 策略有哪些
1.identity自增长 (mysql db2)
2.sequence 自增长(序列) oracle 序列的方式实现自增长
3.native 自动选择
mysql 选择 identity oracle 选择 sequence
4.increment 自增长(会有并发访问的问题,一般在服务器集群环境使用会存在问题。)
指定主键生成策略为手动指定主键的值
assigned
指定主键生成策略为UUID生成的值
uuid
19. 简述hibernate中getCurrentSession和openSession区别
1.getCurrentSession()获得的session与当前的线程进行绑定。而openSessoin()是创建一个新的session
2.getCurrentSession()的事务是由spring控制的。 openSessoin()需要手动开启和关闭事务
3.getCurrentSession需要我们手动设置绑定事务的机制,有三种设置方式,jdbc本地的Thread、JTA、第三种是spring提供的事务管理机制org.springframework.orm.hibernate4.SpringSessionContext,而且srping默认使用该种事务管理机制
20. 为什么在Hibernate的实体类中要提供一个无参数的构造器这一点非常重要?
因为hibernate要通过反射来创建实体类,调用Class.newInstance()。 如果没有无参构造就会报错
21. 可不可以将Hibernate的实体类定义为final类?
是可以的,但是不推荐。 hibernate中的延迟加载使用的是cligb代理,这个代理是实体类的子类。所以实体类最好不要设置为final。
22.Session的清理和清空有什么区别?
1.清理缓存调用的是 session.flush() 方法.
2.清空调用的是 session.clear() 方法.
3.Session清理缓存是指按照缓存中对象的状态的变化来同步更新数据库,但不清空缓存;
4.清空是把Session 的缓存置空, 但不同步更新数据库;
23. Hibernate的优缺点
优点
1. 封装了JDBC,简化了数据访问层繁琐的重复性代码
2. 使用了一级缓存、二级缓存
3. 非侵入性、移植性会好
4. 灵活的映射关系,适应各种数据库。支持复杂的一对多 多对多的方式
缺点
1. 框架使用ORM使得配置复杂
2. 执行效率和原生的JDBC 相比偏差: 特别是在批量数据处理的时候
3. 不支持批量修改和删除
4. 无法对sql进行优化
24. 描述使用 Hibernate 进行大批量更新的经验.
直接通过 JDBC API 执行相关的 SQl 语句或调用相关的存储过程是最佳的方式
25. Hibernate 的OpenSessionView 问题
- 用于解决懒加载异常, 主要功能就是把 Hibernate Session 和一个请求的线程绑定在一起, 直到页面完整输出, 这样就可以保证页面读取数据的时候 Session 一直是开启的状态, 如果去获取延迟加载对象也不会报错。
- 问题: 如果在业务处理阶段大批量处理数据, 有可能导致一级缓存里的对象占用内存过多导致内存溢出, 另外一个是连接问题: Session 和数据库 Connection 是绑定在一起的, 如果业务处理缓慢也会导致数据库连接得不到及时的释放, 造成连接池连接不够. 所以在并发量较大的项目中不建议使用此种方式, 可以考虑使用迫切左外连接 (LEFT OUTER JOIN FETCH) 或手工对关联的对象进行初始化.
- 配置 Filter 的时候要放在 Struts2 过滤器的前面, 因为它要页面完全显示完后再退出.
26. 如何优化Hibernate?
1.使用双向一对多关联,不使用单向一对多
2.灵活使用单向一对多关联
3.不用一对一,用多对一取代
4.配置对象缓存,不使用集合缓存
5.一对多集合使用Bag,多对多集合使用Set
6. 继承类使用显式多态
27. Hibernate悲观锁与乐观锁
1.悲观锁
行级悲观锁:Hibernate总是使用数据库的锁定机制,从不在内存中锁定对象!只要为JDBC连接指定一下隔 离级别,然后让数据库去搞定一切就够了。
2.乐观锁
使用版本号或时间戳来检测更新丢失,在的映射中设置 optimistic-lock=”all”可以在没有版本或者时间戳属性映射的情况下实现 版本检查,此时Hibernate将比较一行记录的每个字段的状态
28. hibernate支持的缓存策略
1.Read-only: 这种策略适用于那些频繁读取却不会更新的数据,这是目前为止最简单和最有效的缓存策略
2.Read/write:这种策略适用于需要被更新的数据,比read-only更耗费资源,在非JTA环境下,每个事务需要在session.close和session.disconnect()被调用
3.Nonstrict read/write: 这种策略不保障两个同时进行的事务会修改同一块数据,这种策略适用于那些经常读取但是极少更新的数据
4.Transactional: 这种策略是完全事务化得缓存策略,可以用在JTA环境下
参考blog
https://blog.csdn.net/wu1317581750/article/details/82530907
https://blog.csdn.net/weixin_30340353/article/details/95160437
https://www.cnblogs.com/yanggb/p/11268377.html