为Spring集成的Hibernate配置二级缓存

  在不少的项目中,也使用到了Hibernate的二级缓存,现在学习一下在Hibernate里面该如何使用二级缓存,先要把以下的配置信息加到beans.xml里的相应位置:
hibernate.cache.use_second_level_cache=true
hibernate.cache.use_query_cache=false
hibernate.cache.provider_class=org.hibernate.cache.EhCacheProvider

beans.xml

Xml代码 复制代码
  1. <?xml version="1.0" encoding="UTF-8"?>  
  2. <beans xmlns="http://www.springframework.org/schema/beans"  
  3.        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
  4.        xmlns:context="http://www.springframework.org/schema/context"  
  5.        xmlns:aop="http://www.springframework.org/schema/aop"  
  6.        xmlns:tx="http://www.springframework.org/schema/tx"  
  7.        xsi:schemaLocation="http://www.springframework.org/schema/beans   
  8.            http://www.springframework.org/schema/beans/spring-beans-2.5.xsd   
  9.            http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd   
  10.            http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd   
  11.            http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd">  
  12.      <context:annotation-config/>  
  13.      <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">  
  14.         <property name="driverClassName" value="org.gjt.mm.mysql.Driver"/>  
  15.         <property name="url" value="jdbc:mysql://localhost:3306/springjdbc?useUnicode=true&amp;characterEncoding=UTF-8"/>  
  16.         <property name="username" value="root"/>  
  17.         <property name="password" value="456"/>  
  18.          <!-- 连接池启动时的初始值 -->  
  19.          <property name="initialSize" value="1"/>  
  20.          <!-- 连接池的最大值 -->  
  21.          <property name="maxActive" value="500"/>  
  22.          <!-- 最大空闲值.当经过一个高峰时间后,连接池可以慢慢将已经用不到的连接慢慢释放一部分,一直减少到maxIdle为止 -->  
  23.          <property name="maxIdle" value="2"/>  
  24.          <!--  最小空闲值.当空闲的连接数少于阀值时,连接池就会预申请去一些连接,以免洪峰来时来不及申请 -->  
  25.          <property name="minIdle" value="1"/>  
  26.       </bean>  
  27.   
  28.     <!--通过这个配置就可以定义一个sessionFactory,这个对象在容器里面只存在一个,它是一个单例的形式-->  
  29.     <bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">  
  30.          <property name="dataSource" ref="dataSource"/> <!--数据源-->  
  31.          <property name="mappingResources">  
  32.             <list>  
  33.               <value>cn/itcast/bean/Person.hbm.xml</value><!--实体bean的映射元数据-->  
  34.             </list>  
  35.          </property>  
  36.          <property name="hibernateProperties">  
  37.             <value>  
  38.                 hibernate.dialect=org.hibernate.dialect.MySQL5Dialect   
  39.                 hibernate.hbm2ddl.auto=update<!--代表要不要根据映射元数据来生成数据库表结构-->  
  40.                 hibernate.show_sql=false <!--是否打印Hibernate执行的sql-->  
  41.                 hibernate.format_sql=false <!--是否要对它进行格式化-->  
  42.                 <!--这两个主要在测试阶段比较有用-->  
  43.   
  44.                 <!--代表使用Hibernate的二级缓存-->  
  45.                 hibernate.cache.use_second_level_cache=true  
  46.                 <!--代表是否使用查询缓存,这里不使用,因为一般而言查询缓存的命中率并不是很高,所以我们没有   
  47.                 必要为每一个用户的查询缓存它的数据,所以这里设为false-->  
  48.                 hibernate.cache.use_query_cache=false  
  49.                 <!--用于指定使用缓存产品的驱动类-->  
  50.                 hibernate.cache.provider_class=org.hibernate.cache.EhCacheProvider   
  51.               </value>  
  52.          </property>  
  53.     </bean>  
  54.   
  55.     <!--配置事务管理,使用的事务管理器是Spring为我们提供的,针对Hibernate的一个事务管理器-->  
  56.     <!--只要是通过sessionFactory对象创建的session都会纳入到这个事务管理器中-->  
  57.     <bean id="txManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">  
  58.         <property name="sessionFactory" ref="sessionFactory"/>  
  59.     </bean>  
  60.   
  61.     <!--配置事务采用的申明方式,事务申明的方式有两种:1种是基于XML的方式,1种是基于注解的方式   
  62.     ,这里是使用注解方式来申明事务-->  
  63.     <!--这段打开了对@Transaction注解的支持,这里用到的事务管理器就是前面提到的txManager-->  
  64.     <tx:annotation-driven transaction-manager="txManager"/>  
  65.   
  66.     <bean id="personService" class="cn.itcast.service.impl.PersonServiceBean"/>  
  67. </beans>  


ehcache这个缓存产品要使用到一个jar文件,是hibernate核心安装包下的:lib/optional/ehcache-1.2.3.jar,Ehcache底下可以定义一个配置文件,Ehcache默认的配置文件ehcache.xml(放在类路径下)

Xml代码 复制代码
  1. <?xml version="1.0" encoding="UTF-8"?>  
  2. <!--   
  3.     defaultCache节点为缺省的缓存策略   
  4.      maxElementsInMemory 内存中最大允许存在的对象数量   
  5.      eternal 设置缓存中的对象是否永远不过期   
  6.      overflowToDisk 把溢出的对象存放到硬盘上(当对象达到1000个的时候,是否会把溢出的【比如1001个】放到硬盘上去)   
  7.      timeToIdleSeconds 指定缓存对象空闲多长时间就过期,过期的对象会被清除掉   
  8.      timeToLiveSeconds 指定缓存对象总的存活时间   
  9.      diskPersistent 当jvm结束是是否持久化对象(当缓存应用关闭的时候是否要把缓存的对象持久化到磁盘上去?)   
  10.      diskExpiryThreadIntervalSeconds 指定专门用于清除过期对象的监听线程的轮询时间   
  11.  -->  
  12. <ehcache>  
  13.     <diskStore path="D:/cache"/><!--缓存的对象存在硬盘的哪个路径底下-->  
  14.   
  15.     <!--defaultCache 定义缓存的一些默认行为-->  
  16.     <defaultCache  maxElementsInMemory="1000" eternal="false" overflowToDisk="true"  
  17.         timeToIdleSeconds="120"  
  18.         timeToLiveSeconds="180"  
  19.         diskPersistent="false"  
  20.         diskExpiryThreadIntervalSeconds="60"/>  
  21.   
  22. </ehcache>  


这是缓存的默认的配置,配置好了这个缓存之后,就可以应用到hibernate里面的实体bean了,我们在需要使用缓存的实体bean的映射元数据配置里面添上缓存配置,
Person.hbm.xml

Hbm代码 复制代码
  1. <?xml version="1.0" encoding="UTF-8"?>   
  2. <!DOCTYPE hibernate-mapping PUBLIC   
  3.         "-//Hibernate/Hibernate Mapping DTD 3.0//EN"  
  4.         "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">   
  5. <hibernate-mapping package="cn.itcast.bean">   
  6.     <class name="Person" table="person">   
  7.         <cache usage="read-write" region="cn.itcast.bean.Person"/>   
  8.         <!--   
  9.         usage:设置缓存的策略,这里使用read-write。两个并发的事务可以对对象进行read,   
  10.             但如果是当一个事务对它write的话,另一个事务是不能对它进行read的   
  11.         region:指定缓存的区域名(可以定义为实体类的全称),在这个区域名里面存放缓存的对象。   
  12.         -->   
  13.         <id name="id">   
  14.             <generator class="native"/>   
  15.         </id>   
  16.         <property name="name" length="10" not-null="true"/>   
  17.     </class>   
  18. </hibernate-mapping>  


这样的话,我们就可以为Person实体bean应用上缓存了,当然我们也可以为cn.itcast.bean.Person这个缓存域来定义一些它的特殊缓存设置,如果不定义的话,就默认使用ehcache.xml里面的<defaultCache/>缓存策略。如果有特别的缓存设置,可以对它进行定义

ehcache.xml

Xml代码 复制代码
  1. <?xml version="1.0" encoding="UTF-8"?>  
  2. <!--   
  3.      defaultCache节点为缺省的缓存策略   
  4.      maxElementsInMemory 内存中最大允许存在的对象数量   
  5.      eternal 设置缓存中的对象是否永远不过期   
  6.      overflowToDisk 把溢出的对象存放到硬盘上(当对象达到1000个的时候,是否会把溢出的【比如1001个】放到硬盘上去)   
  7.      timeToIdleSeconds 指定缓存对象空闲多长时间就过期,过期的对象会被清除掉   
  8.      timeToLiveSeconds 指定缓存对象总的存活时间   
  9.      diskPersistent 当jvm结束是是否持久化对象(当缓存应用关闭的时候是否要把缓存的对象持久化到磁盘上?)   
  10.      diskExpiryThreadIntervalSeconds 指定专门用于清除过期对象的监听线程的轮询时间   
  11.  -->  
  12. <ehcache>  
  13.     <diskStore path="D:/cache"/><!--缓存的对象存在硬盘的哪个路径底下-->  
  14.   
  15.     <!--defaultCache 定义缓存的一些默认行为-->  
  16.     <defaultCache  maxElementsInMemory="1000" eternal="false" overflowToDisk="true"  
  17.         timeToIdleSeconds="120"  
  18.         timeToLiveSeconds="180"  
  19.         diskPersistent="false"  
  20.         diskExpiryThreadIntervalSeconds="60"/>  
  21.     <cache name="cn.itcast.bean.Person" maxElementsInMemory="100" eternal="false"  
  22.     overflowToDisk="true" timeToIdleSeconds="300" timeToLiveSeconds="600" diskPersistent="false"/>  
  23. </ehcache>  


现在已经为Person实体应用上了缓存,我们怎样去检验它目前应用上的缓存呢?我们应用上的缓存可以是这样的:如果一旦缓存里面存在某个id的对象后,当它第二次再去请求相同id的这个对象的时候,它就不会从数据库里获取数据的,而是从内存里面获取到这个缓存对象的,我们根据这点就可以来测试这个缓存是否起作用了?
我们的计划是这样的。。
getPerson(1)
//...把数据库关闭
getPerson(1)

getPerson(1),调用业务bean的getPerson(1)方法获取第一条记录,二级缓存就会把这条记录放到缓存里面去,就是说,当我们第二次再去得到1这个Person的话,它就会从内存里面获取,而不是从数据库里获取。
既然第二次获取是从内存里获取的,也就是说我们在中间把数据库关掉,当第二条getPerson(1)再获取1这个Person,如果说它能获取到,就证明这个对象是从内存获取的,因为这时候数据库已经关闭了,现在就做这么一个实验
PersonServiceTest.java

Java代码 复制代码
  1. package junit.test;   
  2.   
  3. import java.util.List;   
  4.   
  5. import org.junit.BeforeClass;   
  6. import org.junit.Test;   
  7. import org.springframework.context.ApplicationContext;   
  8. import org.springframework.context.support.ClassPathXmlApplicationContext;   
  9.   
  10. import cn.itcast.bean.Person;   
  11. import cn.itcast.service.PersonService;   
  12.   
  13. public class PersonServiceTest {   
  14.     private static PersonService personService;   
  15.   
  16.     @BeforeClass  
  17.     //这个方法是在当单元测试PersonServiceTest实例被构建出来后就会执行   
  18.     //可以在这个方法里面做一些初始化的操作   
  19.     public static void setUpBeforeClass() throws Exception {   
  20.         try {   
  21.             ApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml");   
  22.             personService = (PersonService)applicationContext.getBean("personService");   
  23.         } catch (RuntimeException e) {   
  24.             e.printStackTrace();   
  25.         }   
  26.     }   
  27.   
  28.     .........................................   
  29.   
  30.     @Test  
  31.     public void testGetPerson() {   
  32.         Person person = personService.getPerson(2);   
  33.         System.out.println(person.getName());   
  34.         try {   
  35.             System.out.println("请关闭数据库");   
  36.             Thread.sleep(15*1000);   
  37.         } catch (InterruptedException e) {   
  38.             e.printStackTrace();   
  39.         }   
  40.         System.out.println("第二次开始获取");   
  41.         person = personService.getPerson(2);   
  42.         System.out.println(person.getName());   
  43.     }   
  44.   
  45.     .........................................   
  46.   
  47. }  
package junit.test;

import java.util.List;

import org.junit.BeforeClass;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import cn.itcast.bean.Person;
import cn.itcast.service.PersonService;

public class PersonServiceTest {
    private static PersonService personService;

    @BeforeClass
    //这个方法是在当单元测试PersonServiceTest实例被构建出来后就会执行
    //可以在这个方法里面做一些初始化的操作
    public static void setUpBeforeClass() throws Exception {
        try {
            ApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml");
            personService = (PersonService)applicationContext.getBean("personService");
        } catch (RuntimeException e) {
            e.printStackTrace();
        }
    }

    .........................................

    @Test
    public void testGetPerson() {
        Person person = personService.getPerson(2);
        System.out.println(person.getName());
        try {
            System.out.println("请关闭数据库");
            Thread.sleep(15*1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("第二次开始获取");
        person = personService.getPerson(2);
        System.out.println(person.getName());
    }

    .........................................

}


这个实验主要是证明:当关闭数据库之后,我们再去获取Person2记录,如果它能返回并且正确打印信息,就证明这数据是从缓存(内存)里获取到这对象的,不是从数据库获取对象的,数据库person表如图:


首先要把D:/cache的数据清掉,执行下这个单元测试代码的testGetPerson()方法,其中要手动关闭Mysql数据库,控制台打印出:
李四
请关闭数据库
第二次开始获取
李四


说明:在我们数据库关闭的情况下,它也能获取到person name,也就证明这时候这个对象是从缓存里面获取的。
那么我们二级缓存的应用就已经成功了。二级缓存在企业中也是被大量使用到,所以大家要掌握。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值