Hibernate二级缓存的使用



 

1启用Hibernate二级缓存

Hibernate二级缓存分为两部分,class缓存和查询缓存,其获取对象的方式有所不一样,但二者也有联系,查询缓存必须以class缓存为基础才能起做用,不然只会使效率更低。java

咱们这里使用的二级缓存是经过ehcache第三方插件实现的。spring

1.1配置Hibernate.cfg.xml

启用class缓存:sql

              <property name="hibernate.cache.provider_class">数据库

                     org.hibernate.cache.EhCacheProvider缓存

              </property>session

       启用查询缓存:框架

              <property name="hibernate.cache.use_query_cache">true</property>ide

1.2配置Spring框架中的hibernate

       启用class缓存:spa

<prop key="hibernate.cache.provider_class">org.hibernate.cache.EhCacheProvider</prop>hibernate

启用查询缓存:

<prop key="hibernate.cache.use_query_cache">true</prop>

1.3配置ehcache

       Ehcache配置文件为ehcache.xml,默认配置为:

              <ehcache>

                  <diskStore path="java.io.tmpdir"/>

                  <defaultCache

                   maxElementsInMemory="10000"

                   eternal="false"

                   timeToIdleSeconds="1800"

                   timeToLiveSeconds="1800"

                   overflowToDisk="true"

            />

</ehcache>

       其中各项内容的含义为:

1         diskStore:表明当二级缓存对象数据在内存中溢出,若是须要写入文件系统时的文件目录。

2         defaultCache:默认的calss缓存配置,若是某个对象没有其专有的配置时,ehcache一概启用默认配置。

3         maxElementInMemory:对象在内存中可存放的最大数量。

4         eternal:表示对象永不过时,若是选true56两项无效。

5         timeToIdleSeconds:对象的空闲状态过时时间,单位为秒,0为能够无限制空闲。

6         timeToLiveSeconds:对象存在的最长时间,单位为秒(注意,若是该项比5项要小,则第5项无心义),0为永不过时。

7         overflowToDisk:当对象在内存中的数量超过maxElementInMemory值时,若是该项为true,则ehcahe会把对象数据写入diskStore项指定的目录。

若是须要对某个具体对象进行单独配置时,能够加上一组cache配置,例如:

            <cache name="com.juyee.mp.bean.SysCodelist"

            maxElementsInMemory="10000"

            eternal="true"

            timeToIdleSeconds="1800"

            timeToLiveSeconds="0"

            overflowToDisk="true"

         />

另外还有两个特殊的cache配置:

     <cache name="org.hibernate.cache.UpdateTimestampsCache"

            maxElementsInMemory="5000"

            eternal="true"

            timeToIdleSeconds="1800"

            timeToLiveSeconds="0"             

            overflowToDisk="true"/>

     <cache name="org.hibernate.cache.StandardQueryCache"

            maxElementsInMemory="10000"

            eternal="false"

            timeToIdleSeconds="1800"

            timeToLiveSeconds="0"

            overflowToDisk="true"/>

这两个cache配置对应查询缓存,具体做用以下(摘用别人的描述):

       “当hibernate更新数据库的时候,它怎么知道更新哪些查询缓存呢? hibernate在一个地方维护每一个表的最后更新时间,其实也就是放在上面UpdateTimestampsCache所指定的缓存配置里面。

当经过hibernate更新的时候,hibernate会知道此次更新影响了哪些表。而后它更新这些表的最后更新时间。每一个缓存都有一个生成时间和这个缓存所查询的表,当hibernate查询一个缓存是否存在的时候,若是缓存存在,它还要取出缓存的生成时间和这个缓存所查询的表,而后去查找这些表的最后更新时间,若是有一个表在生成时间后更新过了,那么这个缓存是无效的。

能够看出,只要更新过一个表,那么凡是涉及到这个表的查询缓存就失效了,所以查询缓存的命中率可能会比较低。”

       固然,若是没有这两个配置,则ehcache将为查询缓存启用默认配置。

 

2如何使用class缓存

2.1对象缓存    

Class缓存的做用主要是在内存中保存某个具体对象,当用户第一次经过getiterator方式取出对象时,系统会先从class缓存中去找,若是没有再经过sql语句去数据库中查找相关记录,并将查询到的对象放入内存中。

       实例:对某个对象使用二级缓存,只须要在该对象的hbm文件中配置便可

<cache usage="read-write"/>

       咱们注意到其中usage这个选项,它有多个选择,对应不一样的含义,常常有这两种种:

1         read-only:只对缓存中的对象进行读操做。

2         read-write:当对象被update时,缓存中和数据库中一同被修改(缓存不支持事务回滚)。

2.2关联缓存

目前咱们仅仅实现了对一个对象的缓存,那如何对该对象的关联对象集合进行缓存呢?

实例:对某个对象的关联对象集合的二级缓存,须要在该对象的hbm文件中set配置进行修改

              <set name="children" lazy="true" order-by="treeid asc">

            <cache usage="read-write"/>

                     <key column="PARENTID"/>

                     <one-to-many class="SysCodelist"/>

              </set>           

注意:

1         只对one-to-many有效,并且仅仅缓存的是关联对象的id集合,若是须要实现彻底缓存,则须要对关联的对象也配置成使用二级缓存。

2         集合缓存是独立的,不受关联对象添加、删除的影响,若是要修改集合内容,必须对这个集合自己进行修改,例如:codelist.getChildren().add()

3如何使用查询缓存

       查询缓存,目的是为了将经过list()方法的查询结果存入缓存中,并实现对语句的缓存,若是下次用户在使用这条语句进行查询时,将直接从缓存中获取对象数据。

       这里要注意的是,查询缓存必须配合class缓存使用,若是只启用查询缓存,不对查询对象启用二级缓存,则会大大下降查询效率。

由于,当第一次经过启用查询缓存的session进行语句查询时,系统只执行一次数据库查询将全部的记录取出,并将对象存入class缓存,语句及id集合存入查询缓存;而当用户第二次查询该语句时,系统将先执行去查询缓存中查找,取出全部符合条件的id集合,若是这时候该对象的class缓存没启用或在class缓存中已过时,系统将根据id,一个个去数据库load,其实是进行了1+N次查询。

实际上,在咱们系统中,并非对全部对象都要进行二级缓存,而spring框架中提供的hibernate方法,虽然有getHibernateTemplate().setCacheQueries(),但该方法影响的是全局的配置,一旦启用,将会对不须要缓存的查询形成不良影响。

因而,我本身在hibernateService()中添加了一个方法:

    public List findByCachedQuery(final String hql)

    {

        return (List) getHibernateTemplate().execute(new HibernateCallback() {

            public Object doInHibernate(Session session) throws HibernateException {

                Query queryObject = session.createQuery(hql);

                queryObject.setCacheable(true);

                if (getHibernateTemplate().getQueryCacheRegion() != null) {

                    queryObject.setCacheRegion(getHibernateTemplate().getQueryCacheRegion());

                }

                return queryObject.list();

            }

        }, true);

    }

这样,将只在session范围内启用查询缓存,一旦该session结束了,那么查询缓存也将回复默认配置。

注意:使用时只支持hql

4注意事项

       在使用二级缓存时,注意,全部对数据库的修改都必须走hibernate,若是从其余系统来或使用sql语句来修改数据库相关记录,那么将对二级缓存的数据不会形成影响,换句话说,缓存中的对象数据将和数据库中的不一致。