Hibernate常见⾯试题
⼀、Hibernate⼯作原理
hibernate核⼼接⼝
session:负责被持久化对象CRUD操作
sessionFactory:负责初始化hibernate,创建session对象
configuration:负责配置并启动hibernate,创建SessionFactory
Transaction:负责事物相关的操作
Query和Criteria接⼝:负责执⾏各种数据库查询
hibernate⼯作流程
1、读取并解析Hibernate核⼼配置⽂件l
2、读取并解析Hibernate映射⽂件,创建SessionFactory
3、打开Sesssion
4、创建事务Transation
5、持久化操作
6、提交事务
7、关闭Session
8、关闭SesstionFactory
⼆、什么是 ORM 框架?
对象关系映射
即通过类与数据库表的映射关系,将对象持久化到数据库中
三、Hibernate三级缓存
Hibernate是⼀个持久层框架,经常访问物理数据库,为了降低应⽤程序对物理数据源访问的频次,从
⽽提⾼应⽤程序的运⾏性能。缓存内的数据是对物理数据源中的数据的复制,应⽤程序在运⾏时从缓存读写数据,在特定的时刻或事件会同步缓存和物理数据源的数据
1、⼀级缓存
每个 Session 对象创建出来,就会分配⼀块缓存空间,可以存储 session 对象访问的对象信息。 session 关闭后会⾃动清除缓存,⼿动清除可以⽤session.clear() , session.evict(obj) 。 Session ⼀级缓存是独享。
load/get/save/update/saveorupdate ⽅法处理的对象都会放⼊缓存中
1.⼀级缓存⽣命周期跟⼀个session的⽣命周期相同,最多⼀个请求
2.⼀级缓存就是⼀个Map对象.作⽤:便于对对象的管理
3.⽤session查询的对象,其实都是⼀级缓存的数据
原理:
⽤seession取对象A:
⽣成key==A类全限名+#A.id值
从⼀级缓存的map中该key.
若没有到,从数据中查,并以查到的对象为value,存⼊map.
若有到,直接返回⼀级缓存中的对象,不再发SQL语句
优点:可以减少查询数据库的次数,加快查询速度。
缺点:在批量操作中容易导致内存溢出问题。
2、⼆级缓存
⼆级缓存是SessionFactory 对象缓存,可以被创建出的多个 Session 对象共享、⼆级缓存包含了⼀级缓存。
⽣命周期伴随整个应⽤;作⽤:提⾼性能
⼆级缓存是属于第三⽅的
⼆级缓存默认是关闭的,如果要使⽤需要⼿动开启,下⾯是开启过程:
a.导⼊ehcache ⼯具包和 l 配置⽂件(配置⽂件放到src路径下)
echache⼯具包包括:ehcache-core-2.4.3.jar,hibernate-ehcache-4.2.21.Final.jar,slf4j-api-1.6.1.l ⽂件
b.在 l 中配置参数开启⼆级缓存,启⽤ ehcache
hibernate.cache.use_second_level_cache=ture  //使⽤⼆级缓存
ion.factory_class=EhCacheRegionFactory的全限名  //⼆级缓存是第三⽅,这⼉选的是EhCache 映射⽂件中声明
<class>
<cache usage="缓存策略" region="使⽤的缓存参数"/>
</class>
缓存策略
read-only:只读模式,使⽤不可以更改的表;若被更改,会报错
read-write:⽀持并发的读写,更改缓存数据时候,缓存上锁,其他事务会访问数据库,确保数据的正确性
nonstrict-read-write:不锁的读写,可能从map中取到假数据
transactional:轻量级jave ee 不⽀持
c.在要缓存的对象类型中,指定 @Cache 注解标记
@Entity
@Table(name="user")//表⽰对应的表名
@Cache(usage=CacheConcurrencyStrategy.READ_WRITE)
public class User {
//........
}
什么样的数据适合存放到第⼆级缓存中? 
1 很少被修改的数据 
2 不是很重要的数据,允许出现偶尔并发的数据 
3 不会被并发访问的数据 
4 常量数据 
不适合存放到第⼆级缓存的数据? 
1经常被修改的数据 
2 .绝对不允许出现并发访问的数据,如财务数据,绝对不允许出现并发 
3 与其他应⽤共享的数据。
3、查询缓存
⼀级和⼆级缓存,只能缓存单个对象,如果需要缓存⼀个结果集,必须使⽤查询缓存。
⼿动将查询的列表结果拿去缓存,
1 . 在Hibernate的配置⽂件中
hibernate.cache.use_query_cache=true
2 . 在查询列表前,声明要缓存
- 先去map中查,有就取出
- 没有就去数据库查询,在放⼊map;
查询缓存默认也是关闭的,如需使⽤需要⼿动开启,下⾯是开启过程:
a.针对的对象必需已经开启了⼆级缓存
b.在 l 中添加开启查询缓存的配置
true
c.在查询执⾏前,调⽤ query.setCacheable(true);
下⾯看⼀看测试:
String hql="from User";
Configuration conf=new Configuration();
SessionFactory factory=conf.buildSessionFactory();
Session session1 = factory.openSession();
Query query1 = ateQuery(hql);
query1.setCacheable(true);//设置开启缓存
List list1 = query1.list();
for(Object user:list1){
System.out.println(((User)user).getName());
}
System.out.println("------------------------");
Session session2 = factory.openSession();
Query query2 = ateQuery(hql);
query2.setCacheable(true);
List list2 =query2.list();
for(Object user:list2){
System.out.println(((User)user).getName());
}
极少⽤原因:
1.两条query对象必须要有⼀致的HQL
2.存的是⼀个list,当⼀个成员改变,会导致整个list的改变,效率低.
3.只适⽤于,不能更改的list集合
四、Hibernate⼀对多、多对多配置
类与类之间的关系主要体现在表与表之间的关系进⾏操作,它们都市对对象进⾏操作,我们程序中把所有的表与类都映射在⼀起,它们通过配置⽂件中的many-to-one、one-to-many、many-to-many。
五、hibernate的三种状态之间如何转换
1、Transient 瞬时 :对象刚new出来,还没设id,设了其他值。
2、Persistent 持久:调⽤了save()、saveOrUpdate(),就变成Persistent,有id
3Detached 脱管 : 当session close()完之后,变成Detached。
六、hibernate中session的绑定
session
session是⼀种单实例对象 简单说就是⾃⼰⽤ 别⼈不能⽤。在⼀些项⽬中很多⼈⼀起来操作 所以我们可以把session与我们的本地线程⼀起绑定,本地线程的特点就是执⾏⼀次 从创建到销毁。但我们使⽤完session后 别⼈可以再去使⽤。这种线程的绑定 底层使⽤的是threadLocal原理 ⽽在hibernate中 hibernate框架已经帮我们实现了。
⽅法:
1.在hibernate核⼼配置⽂件中配置。
session如何设置和读取
2.调⽤sessionFactory⾥⾯的⽅法实现
1.配置
<property name="hibernate.current_session_context_class">thread
</property>
2.调⽤⽅法实现
如果你有⼯具类 在⼯具类中调⽤
public static Session getSessionObject(){
CurrentSession();
}
注意 : 在你运⾏前要把session关闭的代码去掉 以为当你运⾏结束时你的session就和本地线程⼀起关闭了
七、hibernate中的事务管理
在Hibernate框架中设置事务的隔离级别,可在l核⼼配置⽂件中添加如下配置:
<!--数值可设置为1、2、4、8-->
<property name="tion.isolation">4</property>
hibernate中事务的应⽤
a、事务在service层管理。
b、确保service层和dao层使⽤的时同⼀个Connection,调⽤getCurrentSession⽅法是从ThreadLocal中获得与线程绑定的session。
c、getCurrentSession必须配置才能使⽤
<!--指定getCurrent获得session与当前线程绑定-->
<property name="hibernate.current_session_context_class">thread</property>
b、getCurrentSession⽅法获得的session对象,会在事务提交时⾃动关闭,不⽤⼿动关闭。
⼋、Hibernate是如何延迟加载?
1.、对于Hibernate get⽅法,Hibernate会确认⼀下该id对应的数据是否存在,⾸先在session缓存中查,然后在⼆级缓存中查,还没有就查询数据库,数据 库中没有就返回null。这个相对⽐较简单,
也没有太⼤的争议。主要要说明的⼀点就是在这个版本(bibernate3.2以上)中get⽅法也会查⼆级缓存!
2.、Hibernate load⽅法加载实体对象的时候,根据映射⽂件上类级别的lazy属性的配置(默认为true),分情况讨论:
(1)若为true,则⾸先在Session缓存中查,看看该id对应的对象是否存在,不存在则使⽤延迟加载,返回实体的代理类对象(该代理类为实体类的⼦类,由CGLIB动态⽣成)。等到具体使⽤该对象(除获取OID以外)的时候,再查询⼆级缓存和数据库,若仍没发现符合条件的记录,则会抛出⼀个ObjectNotFoundException。
(2)若为false,就跟Hibernateget⽅法查顺序⼀样,只是最终若没发现符合条件的记录,则会抛出⼀个ObjectNotFoundException。
九、什么是SessionFactory,她是线程安全么
SessionFactory 是Hibrenate单例数据存储和线程安全的,以⾄于可以多线程同时访问。⼀个SessionFactory 在启动的时候只能建⽴⼀次。SessionFactory应该包装各种单例以⾄于它能很简单的在⼀个应⽤代码中储存.
⼗、hibernate 有⼏种查询⽅式?
1、对象导航查询(objectcomposition)
2、HQL查询
1、属性查询
2、参数查询、命名参数查询
3、关联查询
4、分页查询
5、统计函数
3、Criteria 查询
4、SQLQuery本地SQL查询
⼗⼀、hibernate 实体类可以被定义为 final 吗?
你可以将Hibernate的实体类定义为final类,但这种做法并不好。因为Hibernate会使⽤代理模式在延迟关联的情况下提⾼性能,如果你把实体类定义成final类之后,因为 Java不允许对final类进⾏扩展,所以Hibernate就⽆法再使⽤代理了, 如此⼀来就限制了使⽤可以提升性能的⼿段。
⼗⼆、在 hibernate 中使⽤ Integer 和 int 做映射有什么区别?
hibernate的PO类中 经常会⽤到int 型得变量 这个时候如果使⽤基本类型的变量(int ) 如果数据库中对应的存储数据是 null 时使⽤PO类进⾏获取数据 会出现类型转换异常 如果使⽤的是对象类型(Integer)这个时候则不会报错。
⼗三、get()和 load()的区别?
如果未能发现符合条件的记录,Hibernate get⽅法返回null,⽽load⽅法会抛出⼀个ObjectNotFoundException。
load⽅法可返回没有加载实体数据的代 理类实例,⽽get⽅法永远返回有实体数据的对象。
总之对于get和load的根本区别,hibernate对于 load⽅法认为该数据在数据库中⼀定存在,可以放⼼的使⽤代理来延迟加载,如果在使⽤过程中发现了问题,只能抛异常;⽽对于get⽅ 法,hibernate⼀定要获取到真实的数据,否则返回null。
⼗四、在 hibernate 中 getCurrentSession 和 openSession 的区别是什么?
1、getCurrentSession会绑定当前线程,⽽openSession不会,因为我们把hibernate交给我们的spring来管理之后,我们是有事务配置,这个有事务的线程就会绑定当前的⼯⼚⾥⾯的每⼀个session,⽽openSession是创建⼀个新session。
2、getCurrentSession事务是有spring来控制的,⽽openSession需要我们⼿动开启和⼿动提交事务,
3、getCurrentSession是不需要我们⼿动关闭的,因为⼯⼚会⾃⼰管理,⽽openSession需要我们⼿动关闭。
4、⽽getCurrentSession需要我们⼿动设置绑定事务的机制,有三种设置⽅式,jdbc本地的Thread、JTA、第三种是spring提供的事务管理机制hibernate4.SpringSessionContext,⽽且srping默认使⽤该种事务管理机制
⼗五、hibernate 实体类必须要有⽆参构造函数吗?为什么?
⾸先答案是肯定的。
原因
Hibernate框架会调⽤这个默认构造⽅法来构造实例对象,即Class类的newInstance⽅法 ,这个⽅法就是通过调⽤默认构造⽅法来创建实例对象的 。
当查询的时候返回的实体类是⼀个对象实例,是Hibernate动态通过反射⽣成的。反射的Class.forName(“className”).newInstance()需要对应的类提供⼀个⽆参构造⽅法,必须有个⽆参的构造⽅法将对象创建出来,单从Hibernate的⾓度讲 他是通过反射创建实体对象的所以没有默认构造⽅法是不⾏的,另外Hibernate也可以通过有参的构造⽅法创建对象。
提醒⼀点
如果你没有提供任何构造⽅法,虚拟机会⾃动提供默认构造⽅法(⽆参构造器),但是如果你提供了其他有参数的构造⽅法的话,虚拟机就不再为你提供默认构造⽅法,这时必须⼿动把⽆参构造器写在代码⾥,否则new Xxxx()是会报错的,所以默认的构造⽅法不是必须的,只在有多个构造⽅法时才是必须的,这⾥“必须”指的是“必须⼿动写出来”。
⼗六、如何优化Hibernate?

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。