hibernate总结

来源:互联网 发布:上瘾网络剧发布会视频 编辑:程序博客网 时间:2024/06/06 20:51

1 讲讲一下orm框架 以及各个orm框架的区别

答:o---Object对象。

r---关系数据库。

m---映射文件。

orm可以说是一项为了实现面向对象与关系数据库的不匹配而产生的一种框架,简单的说:orm是通过使用描述对象与关系数据库之间映射的元数据,

将Java程序中的对象通过自动持久化同步到关系数据库,本质上来说就是把数据从一种形式转换成另一种形式。

orm类型 映射关系 开发效率 数据库移植

hibernate: 全自动 实体类和数据库 自动生成sql 不同数据库类型的支持

ibatis: 半自动 实体类和SQL语句 需要编写具体的sql 标准SQL方便移植

2 hibernate 的原理及其步骤

答:1.读取配置(Configuration)*.cfg.xml。

2.使用Configuration创建SessionFactory(线程安全)。

3.使用SessionFactory创建Session(线程不安全,使用本地线程TheradLocal解决)。

SessionFactory提供了两种方式得到session。

1 openSession:得到的session是线程不安全的,可以通过本地线程 Threadlocal机制解决,把session放入Threadlocal中,

达到隔离线程的目的,得到的session需要手动关闭。

2 getCurrentSession可以解决要在事务范围内session 线程不安全问题,因为它总是把session绑定到当前线程,

并且在事务提交的时候自动关闭session。

但需要配置:<propertyname="hibernate.current_session_context_class">thread</property><!--针对jdbc的-->

自动关闭session

4.利用Session启动事务(Transaction)。

5.利用Session进行业务操作。

6.提交事务(调用commit()方法)。

7.关闭Session(调用close()方法)。

3 说出Hibernate的核心类和接口:

答:

Configuration:管理从配置文件(*.cfg.xml)中读取的信息。

SessionFactory:根据配置信息创建一个SessionFactory实例。

Session:持久化方法是通过Session来完成的。

Transaction: 事务管理。

Query:查询接口。

SQLQuerry:sql查询的查询接口。

4 hibernate 实体的3种状态

答:

1.瞬时状态:这种状态一般都是刚new出来,这种状态下的数据还没有与session有关联不能与数据库同步。

2.持久化状态:当数据与session产生关联后就由瞬时状态转变为持久化状态,只有与session产生关联后数据才能同步到数据库。

3.离线状态:这种状态曾经被持久化过,而且数据库中也与之有关联,但是当前session已经关闭,与Session已经没有任何的关联,

数据库中同步的数据是在Session关闭之前最后一次提供的数据,当session关闭之后数据就不能同步到数据库了。

几种状态之间是可以互相转换的:瞬时状态可以通过session进入持久化状态,持久化状态通过关闭Session进入离线状态,

而离线状态可以通过update或saveUpdate等方法回到持久化状态,可以通过Delete回到瞬时状态。

5 hibernate的几种查询方式 hibernate的sql查询接口是什么

答:

1.hql查询:hql是面向对象而不是面向数据库的查询,Query作为hql的查询接口,Query通过Session创建查询语句(查询语句的原来是表名,

现在是属性类名,原来是字段,现在是属性)通过session调用createQuery方法实现语句查询。

hql支持两种查询方式:占位符(问号)与命名参数(冒号),不支持*操作,不适合动态查询。

2.sql查询:SQLQuery就是sql的查询接口,此时查询就是sql语句表名就是表名字段名就是字段名,默认查询出来的list不是属性类对象,

而是Object数组,可以通过SQLQuerry.addEntity(属性类.class)进行转换。

也支持命名参数与占位符,但是它的移植性差。

3.qbc查询:Criteria是qbc的查询接口,这种查询方式不需要sql语句也不需要hql查询方法,不过对于太复杂的查询还是不建议使用,

通过Criteria使用Session创建出来的实例.add(Restrictions.eq("字段",条件))来进行条件查询。

4.qbe查询:通过使用样板来查询数据库中的记录,给出要查询记录的所有字段条件,如果不给出查询条件那么此时从属性类中拿出来的属性

都是等于null或0,因此查不出任何记录。

6 什么是hibernate主键生成机制 举例说明

答:

主键生成机制就是通过在*.hbm.xml文件中generator标签里进行配置,通过使用不同的主键机制而产生不同的主键性能。

如:assigned,主键的生成值完全由用户决定,与底层数据库无关。用户需要维护主键值,在调用session.save()之前要指定主键值。

hilo 会多生成一个表,使用高低位算法生成主键。

increment(英扑来慢特),由hibernate管理主键,自动以递增的方式生成字段值,每次增量为1,该主键必须为Integer类型。

identity(安踢踢),由数据库生成标识符,identity是由数据库自己生成的,但这个主键必须设置为自动增长,前提条件是数据库支持自动增长字段类型,

有可能增长的幅度不一定为1。

uuid,数据类为String类型,由Hibernate 通过128位uuid算法生成16进制数值(编码后以长度32的字符串表示)作为主键。

sequence(赛宽丝) 采用数据库提供的sequence(序列) 机制生成主键。如 Oralce 中的Sequence。

foreign 使用另外一个相关联的对象的标识符作为主键。

native 由Hibernate根据使用的数据库自行判断采用 identity、hilo、sequence 其中一种作为主键生成方式。

7 阐述一下hibernate的映射 在关联映射中一对多 和 多对多 是如何实现的 要注意什么问题?

答:

映射分为四种:

1 基本类型的映射。

2 集合映射:加一个表,主键关联起来,1list映射有序可重复,2 set 无序不可重复,3 bag 无序可重复,4 map映射。

3 级联映射:1 一对一,2 一对多,3 多对多

分为单向映射(一方持有另一方的实体或集合),双向映射(彼此持有对方的实体或集合)。

1. 一对一:1 外键关联,把外键对应的字段加上唯一约束。

2 主键关联,双方共用一个主键,采用的主键生产机制是foreign。

2. 一对多:使用的是级联与反转。

1. 一般使用的是双向关联,在一方放多方的集合,在多方放一方的实体。

2. 反转:1. 如果不用反转hibernate默认由一方维护关联关系的字段,做法是一个一个的对集合里面的数据进行插入,

关联字段为空,之后发一条一条的uodate语句去更新关联字段。

2. 如果用反转 表明将关联关系维护权交给另一方(多方)管理,由多方维护关联字段的话,不会产生update语句,

带来了性能上的提升。

3. 使用反转:在one-to-many或many-to-many的集合定义中使用,inverse=“true”表示该对象不维护关联关系,

该属性的值一般在使用有序集合时设置成false(注意hibernate的缺省值是false),

one-to-many维护关联关系就是更新外键,many-to-many维护关联关系就是在中间表增减记录。

3. 级联:当主对象做操作时候其关联的对象也做与主对象类似的操作,可以减少代码,一般在一方使用,

因为如果在多方使用的话那就没什么意义了。

注意:级联时给关联对象设置id时需要注意,hibernate会对关联的对象进行修改,如果关联对象在数据库不存在的时候会报错。

使用级联删除时需要关联对象持久化,否则报外键约束错误。

3. 多对多:加一个中间表,many-to-many,实则是转成两个一对多,而中间表是放了双方的id作为联合主键,和约束。

使用双向多对多的时候,使他们同时指向一个表,不能会创建两个中间表出来,但只有一个中间表会保存到数据,

并且要指明关联字段维护权的问题,一个使用inverse="false" 一个使用inverse="true",否则会出现主键重复的问题。

4 继承映射:1 每个类一张表,2 每个子类一张表,父类没有表,3 所有类一张表

5 组件映射:它只是一个普通的java类,没有映射文件,但是它不是hibernate的实体,而是实体的一部分,将可重用的部分提取出来,

使它可以进行重用。

8 hibernate的缓存是什么 用来干什么的 什么时候用什么方法刷新缓存 各种缓存里放的是什么东西 使用缓存应该注意什么

答:

1. 缓存是什么:缓存是介于物理数据源与应用程序之间,是数据库数据在内存中的存放临时copy的容器,

其作用是为了减少应用程序对物理数据源访问的次数,从而提高了应用的运行性能。

2. 使用缓存的条件。

1.读取大于修改。

2.数据量不能超过内存容量。

3.可以容忍出现无效数据。

3. 一级缓存,是session共享级别的,hibernate内置的缓存,里面存放的实体,因为它是hibernate内置的缓存不能控制缓存的数量,

所以要注意大批量操作数据时可能造成内存溢出,可以用clear方法清除缓存中的内容。

4. 二级缓存,SessionFactory级共享,是放在配置文件中,实现为可插拔,里面存放实体。

1 如果使用二级缓存就需要在配置文件中配置开发二级缓存,使用evict(属性类.class)方法清除二级缓存。

2 开启二级缓存的步骤:二级缓存的配置和使用。

* 开启二级缓存,修改hibernate.cfg.xml文件

在hibernate的配置文件中使用property属性开启。

<propertyname="hibernate.cache.use_second_level_cache">true</property>

* 指定缓存产品提供商,修改hibernate.cfg.xml文件

指定缓存产品的提供商(EhCache(衣艾去k其)),也是在配置文件中用property属性指定。

<propertyame="hibernate.cache.provider_class">org.hibernate.cache.EhCacheProvider</property>

* 指定那些实体类使用二级缓存(两种方法)

* 在映射文件中采用<cache>标签

<cache usage="read-only"/>

usage="read-only"是“只读”缓存策略,这个<cache>标签只能放在<class>标签的内部,而且必须处在<id>标签的前面。

* 在hibernate.cfg.xml配置文件中,采用<class-cache>标签。

<class-cacheclass="com.lxit.hibernate.Classes" usage="read-only"/>

注意:这个<class-cache>标签必须放在<mapping>标签的后面。

5. 查询缓存,Query,Criteria(查询缓存)由于命中率较低,所以hibernate默认是关闭的。

1 在配置文件中使用property属性打开查询缓存开关。<propertyname="hibernate.cache.use_query_cache">true</property>

2 在程序中手动启用查询缓存query.setCacheable(true)或criteria.setCacheable(true),是先读取查询缓存,再把读出来的数据放入查询缓存中。

SessionFactory中提供了evictQueries()方法用来清除缓存中的内容。

3 如果查询的是实体放入的是id,否则就放入整个结果集。

4 查询缓存里面放的是:

1 查询的list里面放的是实体,会把实体放入的一级缓存与二级缓存里面,则查询缓存里面放的是id,

会根据id到一级缓存与二级缓存里面去找相对于的数据,找不到会发sql到数据库中找。

2 如果查询的list里面放的不是实体,只是查某些字段,查询缓存里面放的是查询的结果集。

6. 使用缓存应该注意什么:

1 使用缓存时应该用于的系统是查询大于修改,因为查询出来的数据会放入缓存中下次直接从缓存中拿出来,不用数据库发sql进行查询,

这样大大提升了系统的性能,而修改过多每次查询都是不同的数据,每次都要重新到数据库中拿值,这样就降低了项目的性能。

2 数据量不能超过内存容量,否则会报系统内存溢出错误。

3. 使用一级缓存的问题,当Session关闭后里面的数据就没有了,因为不能控制,所以要注意大批量操作数据时可能造成内存溢出。

4. 使用二级缓存的问题,要注意它的命中率,如果命中率太低对系统性能的消耗会很大。

7. 查看二级缓存的命中率:

(1) 在hibernate的配置文件中要打开命中率开关,<property name="hibernate.generate_statistics">true</property>。

(2) 通过sessionFactory.getStatistics().getSecondLevelCacheHitCount();,查看命中的次数(是从二级缓存中查询出来的)。

通过sessionFactory.getStatistics().getSecondLevelCacheMissCount());,查看没有命中的次数。

9 load与get save与persistsaveorupdate与merge list与iterator 区别

答:它们的是把数据放入缓存中的。

1 load(漏斗)(支持懒加载)根据id在查询时不会立即访问数据库,而是在需要使用时才会访问数据库,如果id不存在会报找不到id错误。

get(不支持懒加载)根据id查询时会立即访问数据库,如果id不存在则返回null。

2 save(赛屋)保存数据登记相应的动作到对列中,并把实体放入session中,等待flush方法调用同步数据库。

persist(炮赛丝特)在事务外不会产生增加语句,在主键生成机制是native中可以看到。

3 merge(冒杰) 调用merge对象就不会变成持久化状态的,当id在缓存中存在对应的实体时,就是把两个合并。

saveOrUpdate碰到这种情况会报错,因为相同的主键在session中已经存在另一个object。

4 list它是一次性把所有的数据查询出来,而且会把查询出来的数据放入一级缓存中,也会放入二级缓存,会把读出来的数据放入查询缓存中,

但是不使用一级缓存,同样也不使用二级缓存,list会使用查询缓存。

iterator不会把查询出来的数据放入一级缓存中,也不会放入二级缓存,但是使用一级缓存,同样会使用二级缓存,不使用查询缓存,

因为迭代器会先到数据库中把id都取出来,然后真正要遍历某个对象的时候先到缓存中找,如果找不到,以id为条件再发一条sql到数据库,

这样如果缓存中没有数据,则查询数据库的次数为n+1。

项目中用list与iterator:先使用list查询,因为它会把查询出来的数据放入缓存中,然后使用iterator,它会去缓存中查找数据。

10 什么是懒加载(延迟加载) 懒加载用什么技术实现 如何解决session关闭导致的懒加载问题 解决的方案有缺点吗

答:

懒加载:1. 当具体确定用到某个数据时才会去加载数据库,跟我们以前讲的JVM的类装载器差不多,用谁加载谁。

2. 懒加载使用的是代理技术来完成的,代理类就是加载对象的子类(系统定义的),如果把加载对象设置成final修饰那么就不能使用懒加载。

3. 当Session关闭时会造成懒加载的问题,可以使用OpenSessionInView模式来完成懒加载问题,通过过滤器来实现,

在最开始访问过滤器时就把Session打开,直到执行完所有命令返回结果后关闭Session,这样就不会出现懒加载问题。

4. 同样这种方式也带来了问题,事务扩大了,导致资源等待时间过长,session范围变大,如果加载页面的时间过长,

如网速比较慢,内存时间过长,导致系统性能下降,数据库连接不能及时释放。

概念:1 lazy的概念,指在需要数据的时候才发出sql。

2 lazy策略只是在session打开期间才是有效的。

3 Hibernate加载本身就是延迟加载,在*.hbm.xml配置文件中<class>里配置lazy="false"将其改为非延迟加载。

4 Hibernate属性的延迟加载,在*.hnm.xml配置文件中<property>里配置lazy="false"即可。

5 类的延迟加载并不影响属性的延迟加载。

6 连接抓取会使lazy失效。

11 讲讲一下hibernate的抓取策略

答:

hibernate的抓取分为:抓取策略就是抓与当前对象有关联的实体或集合。

连接抓取 fetch="join":通过select语句使用外连接来加载其关联实体或集合。?

查询抓取 fetch="select":在查询当前班级表后会另外发送一条select语句抓取当前对象关联实体或集合。

子查询抓取 fetch="subselect":另外发送一条select语句抓取在前面查询到的所有实体对象的关联实体或集合,通过子查询in完成

批量抓取(batch-size="数量"):给的数量是多少就一次抓取多少条记录(前提是数据库中有那么多记录)。

12 hibernate如何处理大数据量?

答:

1.使用循环方法进行小量同步来清除缓存,当循环方法加载完指定的数量后就调用flush把数据同步到数据库,然后调用clear清除缓存。

2.用(无状态Session)StatelessSession接口:它不和一级缓存、二级缓存交互,也不触发任何事件、监听器、拦截器,

通过该接口的操作会立刻发送给数据库,与JDBC的功能一样。

3.使用Query调用executeUpdate()执行批量更新,会清除相关联的类二级缓存,也可能会造成级联,和乐观锁出现问题。

4.使用分页机制,setFirstResult(2)表示从第3条记录开始。setMaxResults(10)取10条记录。

13 什么是乐观锁与悲观锁?

答:

乐观锁:在数据库中加一个version(版本号),字段属性为int,在读取数据时把版本号一同读出,在更新数据后数据库自动为版本号加1,

如果在更新过程中出现什么情况而没有及时提交,而此时另一个人对此数据进行了更新,更新完后版本号自动加1,

此时数据库中的版本号已经比之前读出的版本号大1,如果提交的版本号小于或等于数据库中的版本号那么就会报当前数据已过期。

* 为什么等于也过期呢?

* 因为提交时版本号会自动加1后再去与数据库中的版本号做比较。

悲观锁:锁住之后在没有提交之前任何人都改变不了原数据,但是有一个问题:在提交之后,

之前没提交时别人修改过但是没有修改成功的数据就会修改成功,使用LockMode.UPGRADE完成。

14 你是如何进行Hibernate的性能优化的

答:

在使用查询数据时第一次使用list方法查询,以后使用迭代方式查询,因为list查询它只会把数据放入缓存中而不会使用缓存,

迭代器查询出的数据它不会放入缓存但是会使用缓存,有一点注意,迭代器不使用查询缓存,list会使用查询缓存。

处理大数据量时使用优化方法(请看第12题的优化方式)。

使用懒加载,关联数据,主键生成机制也是对系统的一种优化。

根据命中率使用缓存,命中率过底部建议使用缓存。

在页面显示时如果有视频就尽量使用懒加载。

关联时使用双向双向映射。

15 讲讲hibernate的监听器 它有什么作用 细说一下hibernate保存数据的步骤?

答: 1. hibernate的数据保存是通过缓存来实现的,通过Configuration加载配置文件来创建SessionFactory,SessionFactory是线程安全的,

使用SessionFactory创建Session,创建Session有两种方式,使用openSession得到的Session是线程不安全的,可以通过本地线程解决这个问题,

需要手动关闭Session,还可以使用getCurrentSession得到的Session是线程安全的,它是自动关闭Session,通过Session调用save或saveOrUpdate方法,

调用方法时会触发一个事件,事件会通知监听器,触发监听器里的方法,然后把对象放进缓存登入动作,等待flush(福拉西)刷新,

提交事务,从缓存中获取数据同步到数据库,一般是指定字符串id。

调用两次flush是否会发两条sql,不会,因为它第一次会发送sql,但是它会登记的动作清除掉,flush是根据登记的动作发送sql的。

2. 自定义监听器

1 实现监听器接口 如:SaveOrUpdateEventListener重写onSaveOrUpdate方法。

2 注册监听器 两种形式:

1 在hibernate的xml里面根据方法配置。

2 通过编程式,可以多个监听器类型之间共享监听器的实例,配置的每次都会产生一个新实例。

hibernate保存数据:调用save方法把对象放进缓存登入动作,等待flush(福拉西)刷新,提交事务,从缓存中获取数据同步到数据库。

16 spring是如何整合hibernate的

答:

1 用spring提供的LocalSessionFactoryBean,创建Sessionfactory,

注入数据源dataSource,hibernate属性hibernateProperties和映射文件。

2 给HibernateTemplate类注入sessionFactory的实例,之后就可以用HibernateTemplate类封装的hibernate的api操作。

3 继承HibernateDaoSupport类使代码更加简洁,给HibernateTemplate类注入sessionFactory,

之后就可以用它的getHibernateTemplate方法获得模板类。

4 事务整合,采用hibernate的事务管理器。

17 你有什么hibernate的最佳实践吗

18 什么是离线查询

答:组装sql时需要Session,查询时不需要Session这是离线查询。

离线查询利用DetachedCriteria类使你在一个session范围之外创建一个查询,并且可以使用任意的Session来执行它,用在动态sql的构建上。

简单说明:就是在Session的范围之外创建查询方式。

19 hibernate查询单条记录有几种方法

答:

唯一记录使用Session调用uinqueResult方法,当你确定本次查询只有一条记录可以用uinqueResult返回一个实体对象。

get方法 load方法。

20 你做项目为什么使用hibernate 为什么不使用hibernate

答:文档齐全,全自动的操作,自动生成sql等功能。

使用hibernate有几方面的好处,它的缓存机制可以为系统查询时节省资源,主键机制,自动生成sql等性能比较强,使用比较灵活,

而且hibernate还可以在不同数据库类型的支持,跨数据库的功能,与底层数据库分离,可移植。

 

不使用hibernate是因为在一些系统里数据量大或是更新比较频繁,而这些原因就会因为hibernate的缓存机制导致系统内存消耗过大,

系统性能下降,还有一些保密性较高的如:财务数据,私人信息等系统也不适合hibernate,不能使用sql的很多功能存储过程等。

jdbc与hibernate不能共存,因为会导致hibernate的缓存失效。

21 用过hibernate注解吗 说出几个

答:

@Entity:标记为持久类映射

@Table:指定表名

@Id

@GeneratedValue

@GenericGenerator:主键生成机制

@OneToMany

@ManyToOne

@JoinColumn:关联字段

 

 

其它注解:

@Resource:标注在对象上,可以代替以前的set方法。

@Controller:表示action层。

@Service:表示service层。

@Repository:表示dao层。

22 hibernate为什么能跨数据库?

答:因为hibernate是ORM模式的框架,ORM就一项专门为了解决面向对象与关系数据库不匹配而产生的一项技术,

因此在它的底层封装了很多数据库的方言,实现了跨数据库的功能,根据配置的方言,产生不同的sql,使用URL通过元数据得到需要使用什么数据库。

使用hibernate碰到什么问题?

1. 大数据量问题。

2. hibernate最好不要与其它系统共存,如:JDBC。

3. 使用一级缓存的问题,当Session关闭后里面的数据就没有了,因为不能控制,所以要注意大批量操作数据时可能造成内存溢出。

4. 使用二级缓存的问题,要注意它的命中率,如果命中率太低对系统性能的消耗会很大。

5. 使用缓存都会有存在无效数据的问题,使用缓存应该注意查询要大于修改,而且数据量不要过大。

 

23 性能优化

1.懒加载

2.List 和 iterator

3.批量处理

4.无状态session

5.分页

 

load()和get()的区别

•       ①:如果数据库中,没有OID 指定的对象。通过 get方法加载,则返回的是一个null;通过load加载,则返回一个代理对象,如果后面代码如果调用对象的某个属性会抛出异常:org.hibernate.ObjectNotFoundException;

②:load 支持延迟加载,get 不支持延迟加载。

优缺点;

•       ①. 优点:

•          > 对 JDBC 访问数据库的代码做了封装,简化了数据访问层繁琐的重复性代码

•          > 映射的灵活性, 它支持各种关系数据库, 从一对一到多对多的各种复杂关系.

•          > 非侵入性、移植性会好

•          > 缓存机制: 提供一级缓存和二级缓存

•       ②. 缺点:

•          > 无法对 SQL 进行优化

•          > 框架中使用 ORM 原则, 导致配置过于复杂

•          > 执行效率和原生的 JDBC相比偏差: 特别是在批量数据处理的时候

•          > 不支持批量修改、删除

 

使用 Hibernate 进行大批量更新的经验.

•       直接通过 JDBC API执行相关的 SQl 语句或调用相关的存储过程是最佳的方式

Hibernate 的OpenSessionView 问题

•       ①. 用于解决懒加载异常, 主要功能就是把Hibernate Session 和一个请求的线程绑定在一起, 直到页面完整输出, 这样就可以保证页面读取数据的时候 Session 一直是开启的状态, 如果去获取延迟加载对象也不会报错。

•       ②. 问题: 如果在业务处理阶段大批量处理数据, 有可能导致一级缓存里的对象占用内存过多导致内存溢出, 另外一个是连接问题:  Session 和数据库Connection 是绑定在一起的, 如果业务处理缓慢也会导致数据库连接得不到及时的释放, 造成连接池连接不够. 所以在并发量较大的项目中不建议使用此种方式, 可以考虑使用迫切左外连接 (LEFT OUTER JOIN FETCH) 或手工对关联的对象进行初始化.

•       ③. 配置 Filter 的时候要放在Struts2 过滤器的前面, 因为它要页面完全显示完后再退出.

Hibernate 中 getCurrentSession()和 openSession() 的区别 ?

•       ①.getCurrentSession() 它会先查看当前线程中是否绑定了 Session, 如果有则直接返回, 如果没有再创建. 而openSession() 则是直接 new 一个新的 Session 并返回。

•       ②. 使用ThreadLocal 来实现线程 Session 的隔离。

•       ③.getCurrentSession() 在事务提交的时候会自动关闭 Session, 而 openSession() 需要手动关闭.

•       Hibernate缓存包括两大类:Hibernate一级缓存和Hibernate二级缓存:

•       1). Hibernate一级缓存又称为“Session的缓存”,它是内置的,不能被卸载。由于Session对象的生命周期通常对应一个数据库事务或者一个应用事务,因此它的缓存是事务范围的缓存。在第一级缓存中,持久化类的每个实例都具有唯一的OID。

•       2). Hibernate二级缓存又称为“SessionFactory的缓存”,由于SessionFactory对象的生命周期和应用程序的整个过程对应,因此Hibernate二级缓存是进程范围或者集群范围的缓存,有可能出现并发问题,因此需要采用适当的并发访问策略,该策略为被缓存的数据提供了事务隔离级别。第二级缓存是可选的,是一个可配置的插件,在默认情况下,SessionFactory不会启用这个插件。

•       当Hibernate根据ID访问数据对象的时候,首先从Session一级缓存中查;查不到,如果配置了二级缓存,那么从二级缓存中查;如果都查不到,再查询数据库,把结果按照ID放入到缓存删除、更新、增加数据的时候,同时更新缓存。

 如何优化Hibernate
1.
使用双向一对多关联,不使用单向一对多
2.
灵活使用单向一对多关联
3.
不用一对一,用多对一取代
4.
配置对象缓存,不使用集合缓存
5.
一对多集合使用Bag,多对多集合使用Set
6.
继承类使用显式多态
7.
表字段要少,表关联不要怕多,有二级缓存撑腰

Hibernate中的查询缓存指的是什么? 这个问题有时是作为上个Hibernate面试问题的后继问题提出的。查询缓存实际上保存的是sql查询的结果,这样再进行相同的sql查询就可以之间从缓存中拿到结果了。为了改善性能,查询缓存可以同二级缓存一起来使用。Hibernate支持用多种不同的开源缓存方案,比如EhCache,来实现查询缓存。

2、update和saveOrUpdate的区别?

  update()和saveOrUpdate()是用来对跨Session的PO进行状态管理的。  
  update()方法操作的对象必须是持久化了的对象。也就是说,如果此对象在数据库中不存在的话,就不能使用update()方法。  
  saveOrUpdate()方法操作的对象既可以使持久化了的,也可以使没有持久化的对象。如果是持久化了的对象调用saveOrUpdate()则会  更新数据库中的对象;如果是未持久化的对象使用此方法,则save到数据库中。

3、hibernate的三种状态之间如何转换  
  当对象由瞬时状态(Transient)一save()时,就变成了持久化状态;  
  当我们在Session里存储对象的时候,实际是在Session的Map里存了一份, 也就是它的缓存里放了一份,然后,又到数据库里存了一份,在缓存里这一份叫持久对象(Persistent)。  Session 一 Close()了,它的缓存也都关闭了,整个Session也就失效了,这个时候,这个对象变成了游离状态(Detached),但数据库中还是存在的。  
  当游离状态(Detached)update()时,又变为了持久状态(Persistent)。  
  当持久状态(Persistent)delete()时,又变为了瞬时状态(Transient), 此时,数据库中没有与之对应的记录。

 

 

Hibernategetload有什么不同之处? 

[如果查询oid不存在,get方法返回nullload方法返回代理对象(代理对象初始化时跑出ObjectNotFoundException]

getload放到一起进行对比是Hibernate面试时最常问到的问题,这是因为只有正确理解get()load()这二者后才有可能高效地使用Hibernateget load的最大区别是,如果在缓存中没有找到相应的对象,get将会直接访问数据库并返回一个完全初始化好的对象,而这个过程有可能会涉及到多个数据库调用;而load方法在缓存中没有发现对象的情况下,只会返回一个代理对象,只有在对象getId()之外的其它方法被调用时才会真正去访问数据库,这样就能在某些情况下大幅度提高性能。你也可以参考Hibernategetload的不同之处, 此链接给出了更多的不同之处并对该问题进行了更细致的讨论。

HibernatesavepersistsaveOrUpdate这三个方法的不同之处? 除了getload,这又是另外一个经常出现的Hibernate面试问题。所有这三个方法,也就是save()saveOrUpdate()persist()都是用于将对象保存到数据库中的方法,但其中有些细微的差别。例如,save()只能INSERT记录,但是saveOrUpdate()可以进行记录的INSERTUPDATE。还有,save()的返回值是一个Serializable对象,而persist()方法返回值为void。你还可以访问savepersist以及saveOrUpdate,找到它们所有的不同之处。如果参数是一个瞬时对象,执行save,如果一个参数是一个update对象,执行update,如果参数是持久化对象,直接返回判断对象的瞬时状态, OIDnullhbm文件中为<id>元素指定unsaved-value属性,如果PO对象OIDunsaved-value也是瞬时对象 
  <id name="id" unsaved-value="-1"> 
如果对象OID-1也是瞬时对象

Hibernate中的命名SQL查询指的是什么? Hibernate的这个面试问题同Hibernate提供的查询功能相关。命名查询指的是用<sql-query>标签在影射文档中定义的SQL查询,可以通过使用Session.getNamedQuery()方法对它进行调用。命名查询使你可以使用你所指定的一个名字拿到某个特定的查询。Hibernate中的命名查询可以使用注解来定义,也可以使用我前面提到的xml影射问句来定义。在Hibernate中,@NameQuery用来定义单个的命名查询,@NameQueries用来定义多个命名查询。

Hibernate中的SessionFactory有什么作用? SessionFactory是线程安全的吗? 这也是Hibernate框架的常见面试问题。顾名思义,SessionFactory就是一个用于创建HibernateSession对象的工厂。SessionFactory通常是在应用启动时创建好的,应用程序中的代码用它来获得Session对象。作为一个单个的数据存储,它也是线程安全的,所以多个线程可同时使用同一个SessionFactoryJava JEE应用一般只有一个SessionFactory,服务于客户请求的各线程都通过这个工厂来获得HibernateSession实例,这也是为什么SessionFactory接口的实现必须是线程安全的原因。还有,SessionFactory的内部状态包含着同对象关系影射有关的所有元数据,它是不可变的,一旦创建好后就不能对其进行修改了。

Hibernate中的Session指的是什么?可否将单个的Session在多个线程间进行共享? 前面的问题问完之后,通常就会接着再问这两个问题。问完SessionFactory的问题后就该轮到Session了。Session代表着Hibernate所做的一小部分工作,它负责维护者同数据库的链接而且不是线程安全的,也就是说,Hibernage中的Session不能在多个线程间进行共享。虽然Session会以主动滞后的方式获得数据库连接,但是Session最好还是在用完之后立即将其关闭。

hibernatesorted collectionordered collection有什么不同? T这个是你会碰到的所有Hibernate面试问题中比较容易的问题。sortedcollection是通过使用JavaComparator在内存中进行排序的,orderedcollection中的排序用的是数据库的orderby子句。对于比较大的数据集,为了避免在内存中对它们进行排序而出现 Java中的OutOfMemoryError,最好使用orderedcollection

Hibernatetransientpersistentdetached对象三者之间有什么区别? Hibernate中,对象具有三种状态:transientpersistentdetached。同Hibernatesession有关联的对象是persistent对象。对这种对象进行的所有修改都会按照事先设定的刷新策略,反映到数据库之中,也即,可以在对象的任何一个属性发生改变时自动刷新,也可以通过调用Session.flush()方法显式地进行刷新。如果一个对象原来同Session有关联关系,但当下却没有关联关系了,这样的对象就是detached的对象。你可以通过调用任意一个sessionupdate()或者saveOrUpdate()方法,重新将该 detached对象同相应的seesion建立关联关系。Transient对象指的是新建的持久化类的实例,它还从未同Hibernate的任何 Session有过关联关系。同样的,你可以调用persist()或者save()方法,将transient对象变成persistent对象。可要记住,这里所说的transient指的可不是Java中的transient关键字,二者风马牛不相及。

HibernateSessionlock()方法有什么作用? 这是一个比较棘手的Hibernate面试问题,因为Sessionlock()方法重建了关联关系却并没有同数据库进行同步和更新。因此,你在使用lock()方法时一定要多加小心。顺便说一下,在进行关联关系重建时,你可以随时使用Sessionupdate()方法同数据库进行同步。有时这个问题也可以这么来问:Sessionlock()方法和update()方法之间有什么区别?。这个小节中的关键点也可以拿来回答这个问题。

Hibernate中二级缓存指的是什么? 这是同Hibernate的缓存机制相关的第一个面试问题,不出意外后面还会有更多这方面的问题。二级缓存是在SessionFactory这个级别维护的缓存,它能够通过节省几番数据库调用往返来提高性能。还有一点值得注意,二级缓存是针对整个应用而不是某个特定的session的。

Hibernate中的查询缓存指的是什么? 这个问题有时是作为上个Hibernate面试问题的后继问题提出的。查询缓存实际上保存的是sql查询的结果,这样再进行相同的sql查询就可以之间从缓存中拿到结果了。为了改善性能,查询缓存可以同二级缓存一起来使用。Hibernate支持用多种不同的开源缓存方案,比如EhCache,来实现查询缓存。

  为什么在Hibernate的实体类中要提供一个无参数的构造器这一点非常重要?

每个Hibernate实体类必须包含一个无参数的构造器,这是因为Hibernate框架要使用ReflectionAPI,通过调用Class.newInstance()来创建这些实体类的实例。如果在实体类中找不到无参数的构造器,这个方法就会抛出一个InstantiationException异常。

  可不可以将Hibernate的实体类定义为final?

是的,你可以将Hibernate的实体类定义为final类,但这种做法并不好。因为Hibernate会使用代理模式在延迟关联的情况下提高性能,如果你把实体类定义成final类之后,因为Java不允许对final类进行扩展,所以Hibernate就无法再使用代理了,如此一来就限制了使用可以提升性能的手段。不过,如果你的持久化类实现了一个接口而且在该接口中声明了所有定义于实体类中的所有public的方法轮到话,你就能够避免出现前面所说的不利后果。

Java开发者的Hibernate面试问答列表就到此为止了。没人会对Hibernate作为ORM解决方案的受欢迎程度产生怀疑,如果你要申请的是JavaJ2EE方面的职位,你就等着人来问你Hibernate方面的面试问题吧。在JEE界,SpringHibernate是两个最流行的Java框架。要是你被问到了其它也值得分享的Hibernate方面的面试问题,别忘了在Java社区中同大家分享一下。

   7.调用session.save()方法,hibernate一定会发出insert语句吗?谈谈你的理解

              re:

             不会,具体执行步骤如下:

                              No1.首先在Session内部缓存中进行查找,如果发现则直接返回。

                             No2. 执行实体类对应的Interceptor.isUnsaved方法(如果有的话),判断对象是否为未保存状态。

                             No3. 根据unsaved-value判断对象是否处于未保存状态。

                             No4. 如果对象未保存(Transient状态),则调用save方法保存对象。

                             No5. 如果对象未已保存(Detached状态),则调用update方法将对象与Session重新关联。

 

   4.为什么Hibernate建议你的实体类实现hashCodeequals方法?

              re:因为Hibernate使用了一级和二级缓存,很多查询为了提高效率Hibernate都会先从缓存中进行查找,然后再从数据库进行查找。而HashCode是唯一的,所以这样避免数据操作出现数据混淆的可能,而equals的作用是对比Hibernate缓存中数据是否一致。

 

 

 

0 0