1. Hibernate缓存是一种提高系统性能的比较好的工具,如果使用合理,则能极大地提高系统性能,但如果使用不合理也会使用系统性能下降。Hibernate缓存比较复杂,要想灵活使用hibernate缓存,必须深入研究hiberante缓存原理,最好能分析hibernate的源代码。有很多人使用hibernate的时间比较长也不能正确理解hibernate缓存,下面我就谈谈hibernate缓存的使用,希望能对大家有点帮助。   
  2.   
  3. Session缓存(一级缓存):当调用Session的保存、更新、查询操作时,在Session缓存中不存在相应对象,则把这些对象加入Session缓存。同一个Session操作,第一次通过ID调用load()或get()查询持久对象,先从Session缓存中查询发现该对象不命中,随即发送一条SQL语句生成一个持久对象并把该对象放入Session缓存。第二次再通过相同ID调用load()或get()查询时将直接从Session缓存将该对象返回,避免多余的数据库连接和查询的开销。   
  4.   
  5. Session的load()和get()方法使用区别:   
  6.   
  7. 1、当数据库不存在对应ID数据时,调用load()方法将会抛出ObjectNotFoundException异常,get()方法将返回null,我比较喜欢使用get()方法。   
  8.   
  9. 2、当对象.hbm.xml配置文件<class>元素的lazy属性设置为true时,调用load()方法时则返回持久对象的代理类实例,此时的代理类实例是由运行时动态生成的类,该代理类实例包括原目标对象的所有属性和方法,该代理类实例的属性除了ID不为null外,所在属性为null值,查看日志并没有Hibernate SQL输出,说明没有执行查询操作,当代理类实例通过getXXX()方法获取属性值时,Hiberante才真正执行数据库查询操作。当对象.hbm.xml配置文件<class>元素的lazy属性设置为false时,调用load()方法则是立即执行数据库并直接返回实体类,并不返回代理类。而调用get()方法时不管lazy为何值,都直接返回实体类。   
  10.   
  11. 3、load()和get()都会先从Session缓存中查找,如果没有找到对应的对象,则查询Hibernate二级缓存,再找不到该对象,则发送一条SQL语句查询。关于这点,很多资料说明get ()不会查询二级缓存,比如夏昕编著的《深入浅出Hibernate》245页描述get()方法不查询二级缓存。但我测试发现load()和get()方法都会查询二级缓存,我上网看了很多缓存方面资料也证实了这点,大家可以看看这篇文章:http://blog.csdn.net/woshichenxu/archive/2006/01/22/586361.aspx   
  12. Session的evict()方法将持久对象从Session缓存中清除,clear()方法将清空整个缓存。   
  13.   
  14. 二级缓存(SesionFactory): 二级缓存由SessionFactory创建的所有Session对象共享使用, 二级缓存可使用第三方的缓存插件,如EHCache、OSChahe、SwarmCache、JBossCache,下面分别介绍二级缓存的类缓存、集合缓存和查询缓存。   
  15.   
  16. 1、类缓存:类缓存的key是持久对象的ID,value为持久化对象POJO,无论调用list(),load()还是iterate()查询,只要读出一个持久化对象POJO,都会根据POJO的ID作为key,value为POJO填充到类缓存中。当通过iterate()方法查询时,先会向数据库发送一条select id from POJO的SQL语句,将所有ID查询出来,再根据ID一个个地作为key到类缓存中查询相应POJO,如果类缓存中存在(命中),则从缓存中返回,否则向数据库发一条select * from POJO  where  id=?语句将查询该对象返回,并填充到类缓存中。当通过list()方法查询时,不会象iterate()先查询ID再查询类缓存,而是直接发送SQL查询数据库将结果返回,但会将查询结果填充到类缓存中,可供itetator()使用。   
  17.   
  18. 配置类缓存的同步策略:在hibernate中启动二级类缓存,需要在hibernate.cfg.xml配置以下参数:   
  19.   
  20. <hibernate-configuration>   
  21.   
  22.  <session-factory>   
  23.     ……   
  24.     <property name=”hibernate.cache.provider_class”>   
  25.      org.hibernate.cache.EhCacheProvider   
  26. <./property>   
  27.  </session-factory>   
  28. </hibernate-configuration>   
  29.  在这里以EHCache配置为例,如果用spring的applicationContext.xml配置,参数为:   
  30. <beans>   
  31.     <bean id="sessionFactory"    
  32. class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">   
  33.    ……   
  34.    <property name="hibernateProperties">   
  35.     ……   
  36.     <prop key="hibernate.cache.provider_class">   
  37. org.hibernate.cache.EhCacheProvider   
  38. </prop>   
  39. ……   
  40. </bean>   
  41. </beans>   
  42. 在这还需要对EHCache进行配置,ehcache.xml配置为:   
  43. <ehcache>   
  44.  <diskStore path="java.io.tmpdir"/>   
  45.  <defaultCache   
  46.     maxElementsInMemory="10000"  
  47.     eternal="false"  
  48.     timeToIdleSeconds="10000"    
  49.     timeToLiveSeconds="10000"    
  50.     overflowToDisk="true"    
  51.  />    
  52.   <cache  name="com.hour41.hibernate.vo.common.City"  
  53.     maxElementsInMemory="10000"  
  54.     eternal="false"  
  55.     timeToIdleSeconds="10000"    
  56.     timeToLiveSeconds="10000"    
  57.     overflowToDisk="true"    
  58.  />   
  59. </ehcache>   
  60.   
  61. 上面配置了默认类缓存和城市类缓存策略:   
  62.   
  63. <diskStore>表示当内存缓存中对象数量超过类设置内存缓存数量时,将缓存对象写到硬盘,path=”java.io.tmpdir”表示把数据写到这个目录下。Java.io.tmpdir目录在运行时会根据相对路径生成。   
  64. <defaultCache>表示设定缓存的默认数据过期策略。   
  65. <cache>表示设定用具体的命名缓存的数据过期策略。   
  66. name表示具体的缓存命名。   
  67. maxElementsInMemory表示cache中最大允许保存的对象数据量。   
  68. eternal表示cache中数据是否为常量。   
  69. timeToIdleSeconds表示缓存数据钝化时间   
  70. timeToLiveSeconds表示缓存数据的生命时间。   
  71. overflowToDisk表示内存不足时,是否启用磁盘缓存。   
  72.   
  73. Hibernate提供了四种缓存同步策略:   
  74.   
  75. read-only策略:只读,对于数据库表的数据不会改变的数据,可以使用只读型缓存。例如城市表的数据不会发生变化,则可配置类缓存为:   
  76.   
  77. <?xml version="1.0" encoding="utf-8"?>   
  78. <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"  
  79. "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">   
  80. <hibernate-mapping>   
  81.     <class name="com.hour41.hibernate.vo.common.City" table="tbl_city" lazy="false" mutable="false">   
  82.        <cache usage="read-only" />   
  83.         <id name="id" type="java.lang.Integer">   
  84.             <column name="cityId" />   
  85.             <generator class="native"></generator>   
  86.         </id>   
  87.         <property name="cnName" type="java.lang.String">   
  88.             <column name="cityCnName"/>   
  89.         </property>   
  90.         <property name="enName" type="java.lang.String">   
  91.             <column name="cityEnName"/>   
  92.         </property>   
  93.         <property name="provinceId" type="java.lang.Integer">   
  94.             <column name="provinceId" />   
  95.         </property>   
  96.    </class>   
  97. </hibernate-mapping>    
  98.   
  99. nonstrict-read-write策略:如果程序对并发数据修改要求不是非常严格,只是偶尔需要更新数据,可以采用本选项,以减少无谓的检查,获得较好的性能。   
  100. read-write策略:严格可读写缓存。   
  101. transactional策略:事务型缓存。
  102. Hibernate缓存是一种提高系统性能的比较好的工具,如果使用合理,则能极大地提高系统性能,但如果使用不合理也会使用系统性能下降。Hibernate缓存比较复杂,要想灵活使用hibernate缓存,必须深入研究hiberante缓存原理,最好能分析hibernate的源代码。有很多人使用hibernate的时间比较长也不能正确理解hibernate缓存,下面我就谈谈hibernate缓存的使用,希望能对大家有点帮助。
    
    Session缓存(一级缓存):当调用Session的保存、更新、查询操作时,在Session缓存中不存在相应对象,则把这些对象加入Session缓存。同一个Session操作,第一次通过ID调用load()或get()查询持久对象,先从Session缓存中查询发现该对象不命中,随即发送一条SQL语句生成一个持久对象并把该对象放入Session缓存。第二次再通过相同ID调用load()或get()查询时将直接从Session缓存将该对象返回,避免多余的数据库连接和查询的开销。
    
    Session的load()和get()方法使用区别:
    
    1、当数据库不存在对应ID数据时,调用load()方法将会抛出ObjectNotFoundException异常,get()方法将返回null,我比较喜欢使用get()方法。
    
    2、当对象.hbm.xml配置文件<class>元素的lazy属性设置为true时,调用load()方法时则返回持久对象的代理类实例,此时的代理类实例是由运行时动态生成的类,该代理类实例包括原目标对象的所有属性和方法,该代理类实例的属性除了ID不为null外,所在属性为null值,查看日志并没有Hibernate SQL输出,说明没有执行查询操作,当代理类实例通过getXXX()方法获取属性值时,Hiberante才真正执行数据库查询操作。当对象.hbm.xml配置文件<class>元素的lazy属性设置为false时,调用load()方法则是立即执行数据库并直接返回实体类,并不返回代理类。而调用get()方法时不管lazy为何值,都直接返回实体类。
    
    3、load()和get()都会先从Session缓存中查找,如果没有找到对应的对象,则查询Hibernate二级缓存,再找不到该对象,则发送一条SQL语句查询。关于这点,很多资料说明get ()不会查询二级缓存,比如夏昕编著的《深入浅出Hibernate》245页描述get()方法不查询二级缓存。但我测试发现load()和get()方法都会查询二级缓存,我上网看了很多缓存方面资料也证实了这点,大家可以看看这篇文章:http://blog.csdn.net/woshichenxu/archive/2006/01/22/586361.aspx
    Session的evict()方法将持久对象从Session缓存中清除,clear()方法将清空整个缓存。
    
    二级缓存(SesionFactory): 二级缓存由SessionFactory创建的所有Session对象共享使用, 二级缓存可使用第三方的缓存插件,如EHCache、OSChahe、SwarmCache、JBossCache,下面分别介绍二级缓存的类缓存、集合缓存和查询缓存。
    
    1、类缓存:类缓存的key是持久对象的ID,value为持久化对象POJO,无论调用list(),load()还是iterate()查询,只要读出一个持久化对象POJO,都会根据POJO的ID作为key,value为POJO填充到类缓存中。当通过iterate()方法查询时,先会向数据库发送一条select id from POJO的SQL语句,将所有ID查询出来,再根据ID一个个地作为key到类缓存中查询相应POJO,如果类缓存中存在(命中),则从缓存中返回,否则向数据库发一条select * from POJO  where  id=?语句将查询该对象返回,并填充到类缓存中。当通过list()方法查询时,不会象iterate()先查询ID再查询类缓存,而是直接发送SQL查询数据库将结果返回,但会将查询结果填充到类缓存中,可供itetator()使用。
    
    配置类缓存的同步策略:在hibernate中启动二级类缓存,需要在hibernate.cfg.xml配置以下参数:
    
    <hibernate-configuration>
    
     <session-factory>
        ……
        <property name=”hibernate.cache.provider_class”>
         org.hibernate.cache.EhCacheProvider
    <./property>
     </session-factory>
    </hibernate-configuration>
     在这里以EHCache配置为例,如果用spring的applicationContext.xml配置,参数为:
    <beans>
        <bean id="sessionFactory" 
    class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
       ……
       <property name="hibernateProperties">
        ……
        <prop key="hibernate.cache.provider_class">
    org.hibernate.cache.EhCacheProvider
    </prop>
    ……
    </bean>
    </beans>
    在这还需要对EHCache进行配置,ehcache.xml配置为:
    <ehcache>
     <diskStore path="java.io.tmpdir"/>
     <defaultCache
        maxElementsInMemory="10000"
        eternal="false"
        timeToIdleSeconds="10000" 
        timeToLiveSeconds="10000" 
        overflowToDisk="true" 
     /> 
      <cache  name="com.hour41.hibernate.vo.common.City"
        maxElementsInMemory="10000"
        eternal="false"
        timeToIdleSeconds="10000" 
        timeToLiveSeconds="10000" 
        overflowToDisk="true" 
     />
    </ehcache>
    
    上面配置了默认类缓存和城市类缓存策略:
    
    <diskStore>表示当内存缓存中对象数量超过类设置内存缓存数量时,将缓存对象写到硬盘,path=”java.io.tmpdir”表示把数据写到这个目录下。Java.io.tmpdir目录在运行时会根据相对路径生成。
    <defaultCache>表示设定缓存的默认数据过期策略。
    <cache>表示设定用具体的命名缓存的数据过期策略。
    name表示具体的缓存命名。
    maxElementsInMemory表示cache中最大允许保存的对象数据量。
    eternal表示cache中数据是否为常量。
    timeToIdleSeconds表示缓存数据钝化时间
    timeToLiveSeconds表示缓存数据的生命时间。
    overflowToDisk表示内存不足时,是否启用磁盘缓存。
    
    Hibernate提供了四种缓存同步策略:
    
    read-only策略:只读,对于数据库表的数据不会改变的数据,可以使用只读型缓存。例如城市表的数据不会发生变化,则可配置类缓存为:
    
    <?xml version="1.0" encoding="utf-8"?>
    <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
    "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
    <hibernate-mapping>
        <class name="com.hour41.hibernate.vo.common.City" table="tbl_city" lazy="false" mutable="false">
           <cache usage="read-only" />
            <id name="id" type="java.lang.Integer">
                <column name="cityId" />
                <generator class="native"></generator>
            </id>
            <property name="cnName" type="java.lang.String">
                <column name="cityCnName"/>
            </property>
            <property name="enName" type="java.lang.String">
                <column name="cityEnName"/>
            </property>
            <property name="provinceId" type="java.lang.Integer">
                <column name="provinceId" />
            </property>
       </class>
    </hibernate-mapping> 
    
    nonstrict-read-write策略:如果程序对并发数据修改要求不是非常严格,只是偶尔需要更新数据,可以采用本选项,以减少无谓的检查,获得较好的性能。
    read-write策略:严格可读写缓存。
    transactional策略:事务型缓存。
    


Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐