Hibernate性能优化(三)

性能优化策略

1.      简介

版本:Hibernate3.2

1.1   目的

1.2   范围

1.3   定义、首字母缩写词和缩略语

1.4   参考资料

1.5   概述

2.      缓存策略

2.1   什么是缓存?

Hibernate 将数据临时存放在内存中,以便加快数据的存取速度。为此,我们可以想象,缓存的实现,就类似于一个Map 对象,首先需要一个key ,以便定位相应被缓存的数据,而它的value 值,便是被缓存的数据。

 

2.2   一级缓存

session 级别的缓存,随着session 的关闭而消失,load/iterator 操作,会从一级缓存中查找数据,如果找不到,再到数据库里面查找。Query.list 操作,如果没有配置查询缓存,将直接从数据库中获取数据。

 

2.3   二级缓存

SessionFactory 级别的缓存。默认的情况下是打开的。这是一个全局缓存策略。它可以对对象的数据进行全局缓存

2.4   查询缓存

即对查询的结果集进行缓存处理,以便下次相同条件相同HQL 的情况下可以直接从缓存中获取数据。

 

3.      二级缓存

3.1.1            如何打开二级缓存?

需要更改hibernate 配置文件:

1、   打开二级缓存( 默认情况下是打开的)

a)        true

2、   指定缓存策略提供商

a)        org.hibernate.cache.EhCacheProvider

 

3.1.2            二级缓存是对对象数据的缓存

为了让hibernate 对对象进行缓存,你必须指定需要缓存哪些类的对象,这有两种方法可以达到这个目的:

1、   hibernate 配置文件中指定,如

2、   在类的映射文件中(即标签下指定),如

read-only />

 

如果你打开了对对象的缓存,那么,所有对这个对象的查询操作的结果,都会被缓存起来。Hibernate 将使用对象的键值作为缓存的key 值,对象的数据作为缓存的value 值。

打开了对象缓存,只有在对对象进行查询操作的时候,才会起作用,如createQuery( from Student ).iterate()

 

3.1.3            缓存策略

缓存有几种形式,可以在映射文件中配置:read-only( 只读,适用于很少变更的静态数据/ 历史数据)nonstrict-read-writeread-write( 比较普遍的形式,效率一般)transactional(JTA 中,且支持的缓存产品较少)

 

 

4.      查询缓存

 

查询缓存的作用,是对list 操作的查询结果集进行缓存!

 

我们使用list 操作的时候,如果启用了查询缓存 hibernate 将根据当前查询的HQL 语句(及其参数值)计算出一个缓存的key 值;查询结果集,将作为缓存的value 值(但如果查询结果集是一个对象结果集的话,其缓存的value 值是对象的ID 集合,而不是对象集合本身 )。

 

可以在hibernate 配置文件中添加:

true

以便打开查询缓存。

 

查询缓存,对对象查询,将缓存其ID 列表;对普通查询,将缓存整个数据集合。所以,对于对象查询,需要配合二级缓存来使用。

 

在打开了查询缓存之后,需要注意,调用query.list() 操作之前,必须显式调用query.setCachable(true) 来标识某个查询使用缓存。

 

 

5.      关于loadgetiteratelist 操作在缓存中的作用

5.1   Load/get

这个方法,用于加载某个对象。如果打开了二级缓存,加载的对象数据将会被缓存。缓存的key 是对象的ID ,缓存的value 是对象的值。

5.2   Iterate

使用iterate 进行查询,分成两种不同的情况:

1、   使用iterate 方法进行对象查询,如createQuery( from Student ).iterate() ,这个时候,如果打开了二级缓存,其加载的对象集合,将会被缓存。缓存的key 为对象的ID 值,缓存的value 是对象的数据。

2、   使用iterate 方法进行其它查询,如createQuery( select name,sex from Student ).iterate() ,这个时候,不管有没有打开二级缓存(以及查询缓存),其查询的结果集都不会进行缓存

 

5.3   List

查询缓存只对list 操作起作用

使用List 进行查询,也分成两种情况:

1、   使用list 方法进行对象查询,如createQuery( from Student ).list() ,这个时候,

a)        如果打开了查询缓存,并使用查询缓存(query.setCachable(true); ),hibernate 将对对象的ID 列表进行缓存

b)        如果同时打开了这个对象的二级缓存,那么hibernate 就会将这个对象的数据加入二级缓存中。

2、   使用list 方法进行普通查询,如createQuery( select name,sex from Student ).list() ,这个时候,

a)        如果打开了查询缓存,并使用查询缓存(query.setCachable(true); ),hibernate 将对查询的结果集进行缓存

b)        不管有没有打开二级缓存,二级缓存的任何设置,对这种类型的查询,不会产生任何影响(因为二级缓存只对对象的数据进行缓存,而不是某些查询结果集)

 

 

5.4   Session 如何与二级缓存交互?

Session 接口通过CacheMode 来定制与二级缓存之间的交互方法:

 

 

 

6.      抓取策略

 

抓取策略,即如何获取数据的策略。

 

下面以下述模型为例:

 

班级与学生模型,之间是一对多双向关联:

 

< hibernate-mapping >

    < class name = "com.bjsxt.hibernate.one2many.Classes" lazy = "false" batch-size = "10" table = "T_Classes" >

       < id name = "id" >

           < generator class = "native" />

       </ id >

       < property name = "name" />

       < set name = "students" inverse = "true" lazy = "false" cascade = "all" >

           < key column = "classesid" />

           < one-to-many class = "com.bjsxt.hibernate.one2many.Student" />

       </ set >

    </ class >

   

    < class name = "com.bjsxt.hibernate.one2many.Student" lazy = "false" table = "T_Student" >

      

       < id name = "id" >

           < generator class = "native" />

       </ id >

       < property name = "name" length = "20" />

       < property name = "sex" length = "10" />

       < many-to-one lazy = "false" name = "classes" column = "classesid" />

    </ class >

</ hibernate-mapping >

 

 

 

·         连接抓取(Join fetching - Hibernate 通过 在SELECT 语句使用OUTER JOIN (外连接)来 获得对象的关联实例或者关联集合。 连接抓取策略可以被定义在或集合(如)标签上。这种抓取策略,对load/get 操作有效。

·         如在Student 的标签上设置fetch=”join” ,当我们load/get 一个Student 的时候,其classes 属性的值,将通过一个outter join 连接查询来获取

·         或在Classes 类的标签上设置fetch=”join” ,当我们load/get 一个Classes 类的实例的时候,其集合数据,也是通过一个outter join 连接查询来抓取

·         查询抓取(Select fetching - 另外发送一条 SELECT 语句抓取当前对象的关联实体或集合。除非你显式的指定lazy="false" 禁止 延迟抓取(lazy fetching ),否则只有当你真正访问关联关系的时候,才会执行第二条select 语句。 这种抓取策略,设置方法为:fetch=”select”

·         如在set 标签上设置fetch=”select”, 下面的查询 List list = session.createQuery("from Classes cls where id in (1,22)").list(); 将产生如下结果:

Hibernate: select classes0_.id as id7_, classes0_.name as name7_ from T_Classes classes0_ where classes0_.id in (1 , 22)

 

Hibernate: select students0_.classesid as classesid1_, students0_.id as id1_, students0_.id as id8_0_, students0_.name as name8_0_, students0_.sex as sex8_0_, students0_.classesid as classesid8_0_ from T_Student students0_ where students0_.classesid=?

 

Hibernate: select students0_.classesid as classesid1_, students0_.id as id1_, students0_.id as id8_0_, students0_.name as name8_0_, students0_.sex as sex8_0_, students0_.classesid as classesid8_0_ from T_Student students0_ where students0_.classesid=?

可见,总共发出:第一,查询 Classes 的数据;第二,因为查询结果集中有两个 Classes 对象,所以针对每个对象,都发出了一个查询语句以便查询其 students 集合的数据。

·          

·         子查询抓取(Subselect fetching - 另外发送一条SELECT 语句抓取在前面查询到(或者抓取到)的所有实体对象的关联集合。除非你显式的指定lazy="false" 禁止延迟抓取(lazy fetching ),否则只有当你真正访问关联关系的时候,才会执行第二条select 语句。 设置方法是:fetch=”subselect”, 它只能被设置在集合映射的属性上。

·         如在set 标签上设置fetch=”sebselect”, 下面的查询 List list = session.createQuery("from Classes cls where id in (1,22)").list();list 对象中,将包含两个Classes 对象的实例,假设其集合上配置lazy=”false”, 我们立刻就能看到hibernatesubselect 抓取策略是:

以下是 hibernate 生成的 SQL 语句:

Hibernate: select classes0_.id as id7_, classes0_.name as name7_ from T_Classes classes0_ where classes0_.id in (1 , 22)

你可能感兴趣的:(Hibernate)