Hibernate面试题部分汇总集合.docx
《Hibernate面试题部分汇总集合.docx》由会员分享,可在线阅读,更多相关《Hibernate面试题部分汇总集合.docx(29页珍藏版)》请在冰豆网上搜索。
Hibernate面试题部分汇总集合
Hibernate常见的面试问题
Hibernate
1.Hibernate简介?
Hibernate是一个开源的对象关系映射框架,它对JDBC进行了非常轻量级的
对象封装,使得Java程序员可以随心所欲的使用面向对象编程思想来操纵数据库。
2.Hibernate工作原理?
及为什么要用?
Hibernate是一个JDO工具。
它的工作原理是通过文件把值对象和数据库表之间建立起一个映射关系,这样,我们只需要通过操作这些值对象和Hibernate
提供的一些基本类,就可以达到使用数据库的目的。
1)对JDBC操作提供封装,方便操作简化数据库访问的代码,使用面向对象的方式操作DAO;
2)简化DAO层的代码量ORM从关系型DB到面向对象(java)的转变;
3)在java代码中充斥着大量的sql语句不便于维护,但是ORM映射可以减少此类代码,便于维护;
3.Hibernate的优点和缺点?
⑴Hibernate的优点:
1).Hibernate使用Java反射机制,而不是字节码增强程序来实现透明性;
2).Hibernate的性能非常好,因为它是一个轻量级框架。
映射的灵活性很出色;
3).它支持多种关系数据库,从一对一到多对多的各种复杂关系;
(2)Hibernate的缺点:
它限制您所使用的对象模型,如一个持久性类不能映射到多个表,其独有的
界面和可怜的市场份额也让人不安。
4.Hibernate的缓存机制?
Hibernate的缓存包括Session的缓存和SessionFactory的缓存,其中
SessionFactory的缓存又可以分为两类:
内置缓存和外置缓存。
Session的缓存是内置的,不能被卸载,也被称为Hibernate的第一级缓存。
SessionFactory的内置缓存中存放了映射元数据和预定义SQL语句,SessionFactory的内置缓存是只读的,应用程序不能修改缓存中的映射元数据和预定义SQL语句,因此SessionFactory不需要进行内置缓存与映射文件的同步。
SessionFactory的外置缓存是一个可配置的插件。
在默认情况下,SessionFactory不会启用这个插
件。
SessionFactory的外置缓存也被称为Hibernate的第二级缓存。
事务范围的缓存是持久化层的第一级缓存;进程范围和集群范围的缓存是持久化层的第二级缓存。
Hibernate还为查询结果提供了一个查询缓存,它依赖于二级缓存。
持久化层可以提供多种范围的缓存。
如果在事务范围的缓存中没有查到相应的数据,还可以到进程范围或集群范围的缓存内查询,如果还是没有查到,那么只有到数据库中查询。
事务范围的缓存是持久化层的第一级缓存,通常它是必需的;进程范围或集群范围的缓存是持久化层的第二级缓存,通常是可选的。
什么样的数据适合放到二级缓存中?
1)很少被修改的数据;
2)不是很重要的数据;
3)不会被并发访问的数据;
4)参考数据。
不适合放到二级缓存中的数据?
1)经常被修改的数据;
2)绝对重要的数据,例如:
财务数据;
3)共享数据。
其它:
·处于一级缓存中的对象永远不会过期,除非应用程序显式清空缓存或者清除
特定的对象必须提供数据
过期策略;
·只要应用程序通过Session接口执行保存、更新、删除、加载和查询数据库数据的操作,Hibernate就会启用第一级缓存,把数据库中的数据以对象的形式拷贝到缓存中,对于批量更新和批量删除操作,如果不希望启用第一级缓存,可以绕过HibernateAPI,直接通过JDBC API来执行指操作。
用户可以在单个类或类的单个集合的粒度上配置第二级缓存。
如果类的实例被经常读但很少被修
改,就可以考虑使用第二级缓存。
只有为某个类或集合配置了第二级缓存,Hibernate在运行时才会把它的实例加入到第二级缓存中。
我的理解:
Hibernate中的一级缓存是出于Hibernate自身的需要而进行的一次数据缓存,可以在Hibernate中的一般操作中起到数据缓存的作用。
而通常所说的缓存
技术,实际上对应的就是Hibernate中的二级缓存,只不过在Hibernate中,已经有了Session级别的一级缓存,所以称之为二级缓存。
缓存的管理:
一级缓存的管理
Session为应用程序提供了两个管理缓存的方法:
1>.Evict(Objectobj):
从缓存中清除参数指定的持久化对象;
2>.Clear():
清空缓存中所有持久化对象。
二级缓存的管理:
Hibernate的二级缓存策略的一般过程如下:
1)条件查询的时候,总是发出一条select*fromtable_namewhere….(选择
所有字段)这样的SQL语句查询数据库,一次获得所有的数据对象。
2)把获得的所有数据对象根据ID放入到第二级缓存中。
3)当Hibernate根据ID访问数据对象的时候,首先从Session一级缓存中查;
查不到,如果配置了二级缓存,那么从二级缓存中查;查不到,再查询数据库,把结果按照ID放入到缓存。
4)删除、更新、增加数据的时候,同时更新缓存。
此外,Hibernate的二级缓存策略,只是针对于ID查询的缓存策略,对于条件查询则毫无作用。
为此,
Hibernate提供了针对条件查询的QueryCache(查询缓存)。
常用的缓存插件:
Hibernate的二级缓存是一个插件,下面是几种常用的缓存插件:
·EhCache:
可作为进程范围的缓存,存放数据的物理介质可以是内存或硬
盘,对Hibernate的查询缓存提供了支持。
·OSCache:
可作为进程范围的缓存,存放数据的物理介质可以是内存或硬
盘,提供了丰富的缓存数据过期策略,对Hibernate的查询缓存提供了支持。
·SwarmCache:
可作为群集范围内的缓存,但不支持Hibernate的查询缓存。
·JBossCache:
可作为群集范围内的缓存,支持事务型并发访问策略,对Hibernate的查询缓存提供了支持。
5.Hibernate是如何实现延迟加载的?
Hibernate对象关系映射提供延迟的与非延迟的对象初始化。
非延迟加载在读取一个对象的时候会将与这个对象所有相关的其他对象一起读取出来。
这有时会导致成百select语句在读取对象的时候执行。
这个问题有时出现在使用双向关系的时候,经常会导致整个数据库都在初始化的阶段被读
出来了。
一个明显的解决方法是使用Hibernate提供的延迟加载机制。
这种初始化策略只在一个对象调用它的一对多或多对多关系时才将关系对象读取出来。
这个过程对开发者来说是透明的,而且只进行了很少的数据库操作请求,因此会得到比
较明显的性能提升。
这项技术的一个缺陷是延迟加载技术要求一个Hibernate会话要在对象使用的时候一直开着。
这会成为通过使用DAO模式将持久层抽象出来时的一个主要问题。
为了将持久化机制完全地抽象出来,所有的数据库逻辑,包括打开或关闭会话,都不能在应用层出现。
最常见的是,一些实现了简单接口的DAO实现类将数据库逻辑完全封装起来了。
一种快速但是笨拙的解决方法是放弃DAO模式,将数据库连接逻辑加到应用层中来。
这可能对一些小的应用程序有效,但是在大的系
统中,这是一个严重的设计缺陷,妨碍了系统的可扩展性。
幸运的是,Spring框架为Hibernate延迟加载与DAO模式的整合提供了一种方便的解决方法。
对那些不熟悉Spring与Hibernate集成使用的人,我不会在这里讨论过多的细节,但是我建议你去了解Hibernate与Spring集成的数据访问。
以一个Web应用为例,Spring提供了OpenSessionInViewFilter和OpenSessionInViewInterceptor。
我们可以随意选择一个类来实现相同的功能。
两种方法唯一的不同就在于interceptor在Spring容器中运行并被配置在web应用的上下文中,而Filter在Spring之前运行并被配置在web.xml中。
不管用哪个,他们都在请求将当前会话与当前(数据库)线程绑定时打开Hibernate会话。
一旦已绑定到线程,这个打开了的Hibernate会话可以在DAO实现类中透明地使用。
这个会话会为延迟加载数据库中值对象的视图保持打开状态。
一旦这个逻辑视图完成了,Hibernate会话会在Filter的doFilter方法或者Interceptor的
postHandle方法中被关闭。
6.Hibernate有几种查询方式?
·Session的get()和load()查询;
·HQL查询;
·Query查询;
·Criteria查询;
·本地SQL语句查询(NativeSQl)。
7.Hibernate的性能优化?
⑴在运行的情况下使用最新版本的Hibernate发行版,如hibernate3中经过优
化的批量处理机制,代理机制、属性的延迟加载支持等;
⑵指定合理的缓存策略,通过系统压力测试得到最佳的缓存性能;
⑶采用合理的Session管理机制,避免无谓的数据库开销和临时对象的反复创建;
⑷尽量使用延迟加载特性,以避免系统资源的无谓消耗;
⑸设定合理的批处理参数(batch_size);
⑹如果可能,使用UUID作为主键生成器;
⑺如果可能,使用基于Version的乐观锁策略替代悲观锁;
⑻开发过程中,打开Hibernate的SQL日志文件(hibernate.show_sql),通过观
察Hibernate生成的SQL
语句进一步了解其实现原理,从而指定更好的实现策略;
⑼数据库本身的优化也起着至关重要的作用,合理的索引、缓存和数据分区策略
都会对持久层性能带来客观提升。
8.Hibernate中的update()和saveOrUpdate()的区别?
Hibernate中的对象状态有3种,分别为:
·未被持久化的值对象(ValueObject,VO);
·已经被持久化的持久化对象(PersistentObject,PO);
·曾经被持久化过,但现在已经和Session分离,以VO的身份在运行。
首先,我们来说说何时用update();
·如果你的PO不需要跨Session,即打开一个Session之后,对其进行操作,之后关闭,再也不会用到了,此时不需要用update()方法,此时Hibernate会自动检测到PO已经被修改过,会向数据库发送一条Update语句;如下代码:
Foofoo=sess.load(Foo.class,id);;
foo.setXXX(xxx);
mit();
·如果你的PO需要跨Session操作,在第一个Session关闭后,你还想把已经于第一个Session分离的PO当做VO来用,并将修改更新到数据库中,那么
此时就需要Update()方法;也就是说,当数据是持久化对象时,不需要使用update方法,当数据不是持久化状态的时候,必须使用update方法,告诉数据库要更新数据;然后,我们谈谈saveOrUpdate();
如果业务层传过来的是一个已经持久化过的PO对象,那么Hibernate就会根据这个方法更新该对象,如果传递过来的是一个VO对象,那么Hibernate就
会save这个对象。
9.Hibernate中的load()和get()的区别?
最重要的区别:
如果未能发现符合条件的记录,Hibernateget方法返回null,而load方法会抛出一个ObjectNotFoundException。
1.对于Hibernateget方法,Hibernate会确认一下该id对应的数据是否存在,首先在session缓存中查找,然后在二级缓存中查找,还没有就查询数据库,数据库中没有就返回null。
2.Hibernateload方法加载实体对象的时候,根据映射文件上类级别的lazy属性的配置(默认为true),分情况讨论:
(1)若为true,则首先在Session缓存中查找,看看该id对应的对象是否存在,不存在则使用延迟加载,返回实体的代理类对象(该代理类为实体类的子
类,由CGLIB动态生成)。
等到具体使用该对象(除获
取OID以外)的时候,再查询二级缓存和数据库,若仍没发现符合条件的记录,则会抛出一个ObjectNotFoundException。
(2)若为false,就跟Hibernateget方法查找顺序一样,只是最终若没发现
符合条件的记录,则会抛出一个ObjectNotFoundException。
注释:
此文出自
Hibernate常用的接口和类
Configuration接口
|-Configuration接口的作用是对Hibernate进行配置,以及对它进行启动。
在Hibernate的启动过程中,Configuration类的实例首先定位映射文档的位置,读取这些配置,然后创建一个SessionFactory对象。
SessionFactory接口
|-这里用到了一个设计模式――工厂模式,用户程序从工厂类SessionFactory中取得Session的实例.SessionFactory并不是轻量级的,一个项目通常只需要一个SessionFactory就够了,但是当你的项目要操作多个数据库时,那你必须为每个数据库指定一个SessionFactory。
SessionFactory在Hibernate中实际起到了一个缓冲区的作用,它缓冲了Hibernate自动生成的SQL语句和一些其它的映射数据,还缓冲了一些将来有可能重复利用的数据。
Session接口
|-Session接口对于Hibernate开发人员来说是一个最重要的接口。
然而在Hibernate中,实例化的Session是一个轻量级的类,创建和销毁它都不会占用很多资源。
这在实际项目中确实很重要,因为在客户程序中,可能会不断地创建以及销毁Session对象,如果Session的开销太大,会给系统带来不良影响。
但值得注意的是Session对象是非线程安全的,因此在你的设计中,最好是一个线程只创建一个Session对象。
Hibernate使用Session来存取,它是持久化管理器接口,代表与数据库之间的一次操作。
然而为了操作持久化数据,首先要获得SessionFactory对象,SessionFactory负责一个数据库,是Session的工厂,对于一个XML配置文件,SessionFactory对象Configuration对象负责创建。
这里的net.sf.hibernate.cfg.Configuration的一个实例代表了应用程序中所有的Java类到关系数据库的映射的集合,这些映射是从一些XML映射文件中编译得到的。
可以得到一个Configuration的实例,直接实例化即可,当所有的映射都被Configuration解析之后,应用程序为了得到Session实例,必须先得到它的工厂,这些工厂应该是应用程序的所有线程所共享的。
当然Hibernate并不禁止程序实例化多个SessionFactory,这在使用不止一个数据库时候就很有用。
Transaction接口
|-Transaction接口是一个可选的API,你可以选择不使用这个接口,取而代之的是Hibernate的设计者自己写的底层事务处理代码。
Transaction接口是对实际事务实现的一个抽象,这些实现包括JDBC的事务、JTA中的UserTransaction、甚至可以是CORBA事务。
之所以这样设计是能让开发者能够使用一个统一事务的操作界面,使得自己的项目可以在不同的环境和容器之间方便地移值。
Query和Criteria接口
|-Query接口让你方便地对数据库及持久对象进行查询,它可以有两种表达方式:
HQL语言或本地数据库的SQL语句。
Query经常被用来绑定查询参数、限制查询记录数量,并最终执行查询操作。
Criteria接口与Query接口非常类似,它允许你创建并执行面向对象的标准化查询。
值得注意的是Query接口也是轻量级的,它不能在Session之外使用。
Callback接口
当一些有用的事件发生时――例如持久对象的载入、存储、删除时,Callback接口会通知Hibernate去接收一个通知消息。
一般而言,Callback接口在用户程序中并不是必须的,但你要在你的项目中创建审计日志时,你可能会用到它。
本文来自CSDN博客,转载请标明出处:
Hibernate管理Session对象的方式有哪些?
尽管让程序自主管理Session对象的生命周期也是可行的,但是在实际Java
应用中,把管理Session对象的生命周期交给Hibernate,可以简化Java应用的程序代码和软件架构。
Hibernate自身提供了3种管理Session对象生命周期的方式:
(1)Session对象的生命周期与本地线程绑定。
(2)Session对象的生命周期与JTA事务绑定。
(3)Hibernate委托程序管理Session对象的生命周期。
它包含了业务逻辑代码,创建SessionFactory对象的代码、管理Session对
象的代码,以及执行数据库事务的代码。
对于复杂的软件应用,需要细分BusinessService类的功能,建立精粒度的对象模型。
精粒度的对象模型把功能逐步分解为多个模块,然后分配给多个类来协作完成。
精粒度的对象模型可以减少重复代码,而且能提高每个类的独立性,有利于软件的维护和可重用。
本节将进一步细分BusinessService类的功能,并且由多个类来分担BusinessService类的功能:
● HibernateUtil类:
实用类,负责创建一个应用范围内的SessionFactory
对象,它的getSessionFactory()静态方法返回这个SessionFactory对象。
它的getCurrentSession()静态方法返回当前的Session对象。
● Monkey类:
持久化类,代表猴子。
● MonkeyDAo.类:
封装了通过HibernateAPI来访问数据库,进行查询及
更新Monkey对象的代码。
不负责声明数据库事务。
DAO(DataAccessObject)
表示数据访问对象。
● BusinessService类:
负责处理投票业务,通过MonkeyDAO类来查询及
更新Monkey对象,数据库事务的声明由BusinessService类来完成。
SessionFactory对象是重量级对象,在一个Java应用中,对于一个数据库存储
源,只需要创建一个代表该存储源的SessionFactory对象,它被整个Java应
用共享。
MonkeyDAO类封装了与Monkey对象有关的访问数据库的代码,参见例程
16-2。
MonkeyDAO类通过HibernateUtil类的getCurrentSession()方法来得到
当前的Session对象。
MonkeyDAO类的getById()及update()方法既不用管理Session,也不用声明事务。
packagemypack;
publicc1assMonkeyDAO(
pub1icMonkeygetById(longid)(
return(Monkey)HibernateUtil.getCurrentSession()
.get(Monkey.class,newLong(id));
publicvoidupdate(Monkeymonkey)(
HibernateUtil.getCurrentSession()·saveOrUpdate(monkey)i)
Hibernate到底如何管理Session对Java应用是透明的。
无论是那种管理方
式,MonkeyDAO类都不必自己创建 Session对象,只需调用 HibernateUtil类的getCurrentSession()方法,就能获得当前的Session对象。
而HibernateUtil类的getCurrentSession()方法实际上是调用SessionFactory对象的getCurrentSession()方法,来获得当前的Session对象。
由此可见,Hibernate内部封装了管理Session对象的生命周期的实现细节。
当Java应用改变Hibernate的Session管理方式时,无须修改Monkey类、MonkeyDAO类和HibernateUtil类的源代码,只需修改Hibernate的配置文件及
BusinessService类就行了。
在Hibernate的配置文件中,hibernate.current-sessioncontext-class属性用于指定Session管理方式,可选值包括:
●thread:
Session对象的生命周期与本地线程绑定。
●jta:
Session对象的生命周期与JTA事务绑定。
●managed:
Hibernate委托程序来管理Session对象的生命周期。
本文固定链接:
Hibernate中的Cache管理
一级Cache:
Session实现了第一级HibernateCache,它属于事务级数据缓冲。
一旦事务结束,这个Cache也随之失效。
一个Session的生命周期对应一个数据库事务或一个程序事务。
Session-cache保证了一个Session中两次请求同一个对象时,取得的对象是同一个JAVA实例,有时它可以避免不必要的数据冲突。
另外,它还能为另一些重要的性能提供保证:
1:
在对一个对象进行自我循环引用时,不至于产生堆栈溢出。
2:
当数据库事务结束时,对于同一个数据库行,不会产生数据冲突,因为对于数据库中的一行,最多只有一个对象来表示它。
3:
一个事务中可能会有很多个处理单元,在每一个处理单元中做的操作都会立即被另外的处理单元得知。
我们不用刻意去打开Session-cache,它总是被打开并且不能被关闭。
当使用save(),update()或saveOrUpdate()来保存数据更改,或通过load(),find(),list()等方法来得到对象时,对象就会被加入到Session-cache.
如果要同步很多数据对象,就需要有效地管理Cache,可以用Session的evict()方法从一级Cache中移除对象。
Sessionsession=HibernateUtil.currentSession();
Transactiontx=session.beginTransaction();
for(inti