现在的位置: 首页 > 综合 > 正文

hibernate的一级缓存、二级缓存、查询缓存

2017年12月27日 ⁄ 综合 ⁄ 共 3151字 ⁄ 字号 评论关闭

链接:http://www.cnblogs.com/xiaoluo501395377/p/3377604.html
一级缓存(session级别)
二级缓存、查询缓存(sessionFactory级别)
二级缓存缓存的仅仅是对象

---使用hibernate二级缓存,我们首先需要对其进行配置,配置步骤如下:
1.hibernate并没有提供相应的二级缓存的组件,所以需要加入额外的二级缓存包,常用的二级缓存包是EHcache。这个我们在下载好的hibernate的lib->optional->ehcache下可以找到(我这里使用的hibernate4.1.7版本),然后将里面的几个jar包导入即可。
2.在hibernate.cfg.xml配置文件中配置我们二级缓存的一些属性:

	<!-- 开启二级缓存 -->
	<property name="hibernate.cache.use_second_level_cache">true</property>
	<!-- 二级缓存的提供类 在hibernate4.0版本以后我们都是配置这个属性来指定二级缓存的提供类-->
	<property name="hibernate.cache.region.factory_class">org.hibernate.cache.ehcache.EhCacheRegionFactory</property>
	<!-- 二级缓存配置文件的位置 -->
	<property name="hibernate.cache.provider_configuration_file_resource_path">ehcache.xml</property>
	
	<!--二级缓存的提供类 如果是使用hibernate3的版-->
	<property name="hibernate.cache.provider_class">net.sf.ehcache.hibernate.EhCacheProvider</property>

3.配置hibernate的二级缓存是通过使用 ehcache的缓存包,所以我们需要创建一个 ehcache.xml 的配置文件,来配置我们的缓存信息,将其放到项目根目录下

<ehcache>
  <!--指定二级缓存存放在磁盘上的位置-->
	<diskStore path="user.dir"/>  
	
  <!--我们可以给每个实体类指定一个对应的缓存,如果没有匹配到该类,则使用这个默认的缓存配置-->
	<defaultCache
		maxElementsInMemory="10000"  //在内存中存放的最大对象数
		eternal="false"         //是否永久保存缓存,设置成false
		timeToIdleSeconds="120"    
		timeToLiveSeconds="120"    
		overflowToDisk="true"     //如果对象数量超过内存中最大的数,是否将其保存到磁盘中,设置成true
		/>  
  <!--
    1、timeToLiveSeconds的定义是:以创建时间为基准开始计算的超时时长;
    2、timeToIdleSeconds的定义是:在创建时间和最近访问时间中取出离现在最近的时间作为基准计算的超时时长;
    3、如果仅设置了timeToLiveSeconds,则该对象的超时时间=创建时间+timeToLiveSeconds,假设为A;
    4、如果没设置timeToLiveSeconds,则该对象的超时时间=max(创建时间,最近访问时间)+timeToIdleSeconds,假设为B;
    5、如果两者都设置了,则取出A、B最少的值,即min(A,B),表示只要有一个超时成立即算超时。
  -->

  <!--可以给每个实体类指定一个配置文件,通过name属性指定,要使用类的全名-->
	<cache name="com.xiaoluo.bean.Student"
		maxElementsInMemory="10000"
		eternal="false"
		timeToIdleSeconds="300"
		timeToLiveSeconds="600"
		overflowToDisk="true"
		/>
	<cache name="sampleCache2"
		maxElementsInMemory="1000"
		eternal="true"
		timeToIdleSeconds="0"
		timeToLiveSeconds="0"
		overflowToDisk="false"
		/> -->
</ehcache>

4.开启我们的二级缓存 

@Entity
	@Table(name="t_student")
	@Cache(usage=CacheConcurrencyStrategy.READ_ONLY)  //表示开启二级缓存,并使用read-only策略
	
	//二级缓存的使用策略一般有这几种:read-only、nonstrict-read-write、read-write、transactional。注意:我们通常使用二级缓存都是将其配置成 read-only ///即我们应当在那些不需要进行修改的实体类上使用二级缓存,否则如果对缓存进行读写的话,性能会变差,这样设置缓存就失去了意义。

---二级缓存不会缓存我们的hql查询语句,要想解决这个问题,我们就要配置查询缓存:

查询缓存也是sessionFactory级别的缓存
只有当 HQL 查询语句完全相同时,连参数设置都要相同,此时查询缓存才有效
因为查询缓存缓存的也仅仅是对象的id,所以第一条 sql 也是将对象的id都查询出来,但是当我们后面如果要得到每个对象的信息的时候,此时又会发sql语句去查询,所以,如果要使用查询缓存,我们一定也要开启我们的二级缓存,这样就不会出现 N+1 问题了
步骤:
1.我们如果要配置查询缓存,只需要在hibernate.cfg.xml中加入一条配置即可:
  <!-- 开启查询缓存 -->
<property name="hibernate.cache.use_query_cache">true</property>
2.然后我们如果在查询hql语句时要使用查询缓存,就需要在查询语句后面设置这样一个方法:
List<Student> ls = session.createQuery("from Student where name like ?")
.setCacheable(true)  //开启查询缓存,查询缓存也是SessionFactory级别的缓存
.setParameter(0, "%王%")
.setFirstResult(0).setMaxResults(50).list();
3.如果是在annotation中,我们还需要在这个类上加上这样一个注解:@Cacheable

---N+1问题:
我们看到,当如果通过iterator()方法来获得我们对象的时候,hibernate首先会发出1条sql去查询出所有对象的id值,当我们如果需要查询到某个对象的具体信息的时候,hibernate此时会根据查询出来的id值再发sql语句去从数据库中查询对象的信息,这就是典型的N+1的问题。
那么这种N+1问题我们如何解决呢,其实我们只需要使用list()方法来获得对象即可。但是既然可以通过list()我们就不会出现N+1的问题,那么我们为什么还要保留iterator()这种形式呢?

---注意的问题-链接:http://developer.51cto.com/art/201202/315922.htm
http://wlh269.iteye.com/blog/341378

抱歉!评论已关闭.