hibernate 的缓存详解

8人阅读 评论(0) 收藏 举报

Hibernate ehcache缓存配置详解+实战

原创 2017年01月10日 16:37:23

依赖管理

我这里使用的maven来管理的依赖,pom如下:

<dependency>
    <groupId>org.hibernate</groupId>
    <artifactId>hibernate-core</artifactId>
    <version>5.0.2.Final</version>
</dependency>
<dependency>
    <groupId>org.hibernate</groupId>
    <artifactId>hibernate-ehcache</artifactId>
    <version>5.0.2.Final</version>
</dependency>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

开始配置缓存

使用ehcache需要配置文件:ehcache.xml 并修改hibernate的配置

ehcache.xml配置详解

配置文件如下:

<ehcache>  
  <!-- 
  指定二级缓存存放在磁盘上的位置,可以使用磁盘目录,也可以使用Java System Property目录,user.home是用户目录、user.dir是用户当前工作目录、java.io.tmpdir是默认临时文件路径 
  -->
   <diskStore path="java.io.tmpdir/cache"/>

  <defaultCache
        maxElementsInMemory="10000"
        eternal="false"
        timeToIdleSeconds="120"
        timeToLiveSeconds="120"
        overflowToDisk="true"
        />

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

    <cache name="sample"
        maxElementsInMemory="1000"
        eternal="true"
        timeToIdleSeconds="0"
        timeToLiveSeconds="0"
        overflowToDisk="false"
        />
</ehcache>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31

cache字段说明:

  1. name:Cache的唯一标识。
  2. maxElementsInMemory:内存中最大缓存对象数。
  3. eternal:Element是否永久有效,一旦设置true,timeout将不起作用。
  4. timeToIdleSeconds:设置Element在失效前的允许闲置时间。仅当element不是永久有效时使用,可选属性,默认值是0,也就是可闲置时间无穷大。
  5. timeToLiveSeconds:设置Element在失效前允许存活时间。最大时间介于创建时间和失效时间之间。仅当element不是永久有效时使用,默认是0.,也就是element存活时间无穷大。
  6. overflowToDisk:配置此属性,当内存中Element数量达到maxElementsInMemory时,Ehcache将会Element写到磁盘中。
  7. maxElementsOnDisk:磁盘中最大缓存对象数,若是0表示无穷大。
  8. memoryStoreEvictionPolicy:当达到maxElementsInMemory限制时,Ehcache将会根据指定的策略
  9. 去清理缓存中的内容。默认策略是LRU(最近最少使用),你也可以设置为FIFO(先进先出)或是LFU(较少使用)

Hibernate二级缓存逻辑:

会先根据entity的region到ehcache的缓存区域查找缓存,region对应的是ehcache配置中的name字段,如果找不到,会使用entity的全类名来查找缓存,如果还找不到会使用default设置

Hibernate缓存设置

xml配置如下:

<!-- 开启二级缓存 -->
<prop key="hibernate.cache.use_second_level_cache">true</prop>
<!-- 开启查询缓存 -->
<prop key="hibernate.cache.use_query_cache">true</prop>
<!-- 高速缓存提供程序 -->
<!-- Hibernate4.0 以前使用该设置<prop key="hibernate.cache.provider_class">net.sf.ehcache.hibernate.SingletonEhCacheProvider</prop>-->
<prop key="hibernate.cache.region.factory_class">org.hibernate.cache.ehcache.SingletonEhCacheRegionFactory</prop>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

实体类注解:

@Cache(region = "sample", usage = CacheConcurrencyStrategy.READ_WRITE)
public class User {
    @Cache(region = "all", usage = CacheConcurrencyStrategy.READ_WRITE)
    private Set<Role> roles = new HashSet<Role>();
}
  • 1
  • 2
  • 3
  • 4
  • 5

usage提供的事务隔离级别有NONE, READ_ONLY, NONSTRICT_READ_WRITE, READ_WRITE, TRANSACTIONAL,但是ehcache不支持TRANSACTIONAL。

使用并测试缓存效果

二级缓存适用于以下数据:

  1. 很少被修改,大量查询的
  2. 不是很重要的数据,允许出现偶尔并发访问的

Hibernate的缓存模式

Hibernate的二级缓存只会根据ID进行缓存,也就是使用get/load方法会将查询对象缓存,如果需要对HQL或SQL进行缓存,则需要在代码中指定setCacheable(true)
查询缓存所缓存的key值就是查询所使用的HQL或SQL语句,需要注意的是:查询缓存不仅要求所使用的HQL语句、SQL语句相同,甚至是要求所传入的参数也相同,Hibernate才能从缓存中查去数据。

1、get方法缓存测试

测试代码:

    /**
     * service.get方法直接使用Hibernate Session.get(class, id)
     */
    @Test
    public void testGet() {
        DynamicProperty dp1 = service.get(1L);
        System.out.println(dp1);
        DynamicProperty dp2 = service.get(1L);
        System.out.println(dp2);
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

输出结果:

Hibernate: select dynamicpro0_.id as id1_1_0_, dynamicpro0_.author as author2_1_0_(省略)from dynamic_property dynamicpro0_ where dynamicpro0_.id=?
com.teemo.entity.DynamicProperty@5147788d
com.teemo.entity.DynamicProperty@50ab025b
  • 1
  • 2
  • 3

从结果中可以看到,第二次查询命中缓存,没有发出SQL查询。

2、根据字段查询,不指定setCacheable(true)

测试代码:

    /**
     * service.get方法使用Query query = getSession().createQuery(hql);
     * query.list来返回结果,没有指定query的setCacheable
     */
    @Test
    public void testGetByProperty() {
        String key = "System.Version";
        DynamicProperty dp1 = service.get("dynamicPropertyKey", key);
        System.out.println(dp1);
        DynamicProperty dp2 = service.get("dynamicPropertyKey", key);
        System.out.println(dp2);
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

输出结果:

Hibernate: select dynamicpro0_.id as id1_1_, dynamicpro0_.author as author2_1_(省略)from dynamic_property dynamicpro0_ where dynamicpro0_.property_key=?
com.teemo.entity.DynamicProperty@5e7e7944

Hibernate: select dynamicpro0_.id as id1_1_, dynamicpro0_.author as author2_1_(省略)from dynamic_property dynamicpro0_ where dynamicpro0_.property_key=?
com.teemo.entity.DynamicProperty@74542394
  • 1
  • 2
  • 3
  • 4
  • 5

对于没有指定query.setCacheable(true)的查询,没有使用缓存对象

3、根据字段查询,不指定setCacheable(true),但是主对象包含List/Set

List/Set中的对象,属于查询缓存

测试代码:

    @Test
    public void testGetByEmail() {
        String email = "mayun@alibaba.com";
        User user1 = userService.get("email", email);
        System.out.println(user1);
        User user2 = userService.get("email", email);
        System.out.println(user2);
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

输出结果:

Hibernate: select user0_.id as id1_6_, user0_.create_time as create_t2_6_(省略)from user user0_ where user0_.email=?

Hibernate: select roles0_.user_id as user_id1_8_0_, roles0_.role_id as role_id2_8_0_(省略)from user_role roles0_ inner join role role1_ on roles0_.role_id=role1_.id where roles0_.user_id=?

Hibernate: select resourcepe0_.role_id as role_id4_5_0_, resourcepe0_.id as id1_5_0_, resourcepe0_.id as id1_5_1_(省略)from role_resource_permission resourcepe0_ where resourcepe0_.role_id=?
com.teemo.entity.User@1e6923ba

Hibernate: select user0_.id as id1_6_, user0_.create_time as create_t2_6_(省略)from user user0_ where user0_.email=?
com.teemo.entity.User@4cd29ffa
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

从结果中可以看出,在第一次查询User实体时,会出现1+N的情况,先查出User实体,在根据User实体查出关联Role,但是此时会把Role的id放到查询缓存中,对象放到二级缓存中,在第二次查询时,发现查询缓存存在这些Role id,那么就会到二级缓存中查询到响应的对象,所以第二次查询没有发出Role相关的SQL。

4、根据字段查询,指定setCacheable(true)

测试代码:

    @Test
    public void testGetByEmail() {
        String email = "mayun@alibaba.com";
        User user1 = userService.get("email", email);
        System.out.println(user1);
        User user2 = userService.get("email", email);
        System.out.println(user2);
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

输出结果:

2017-01-10 16:21:19.843 [main] DEBUG org.hibernate.cache.internal.StandardQueryCache  - Checking cached query results in region: org.hibernate.cache.internal.StandardQueryCache
2017-01-10 16:21:19.843 [main] DEBUG org.hibernate.cache.ehcache.internal.regions.EhcacheGeneralDataRegion  - key: sql: select user0_.id as id1_6_, user0_.create_time as create_t2_6_, user0_.deleted as deleted3_6_, user0_.department_key as departme4_6_, user0_.email as email5_6_, user0_.mobile_phone as mobile_p6_6_, user0_.modify_time as modify_t7_6_, user0_.nickname as nickname8_6_, user0_.password as password9_6_, user0_.salt as salt10_6_, user0_.status as status11_6_, user0_.username as usernam12_6_ from user user0_ where user0_.email=?; parameters: ; named parameters: {email_0=mayun@alibaba.com}; transformer: org.hibernate.transform.CacheableResultTransformer@110f2
2017-01-10 16:21:19.844 [main] DEBUG org.hibernate.cache.ehcache.internal.regions.EhcacheGeneralDataRegion  - Element for key sql: select user0_.id as id1_6_, user0_.create_time as create_t2_6_, user0_.deleted as deleted3_6_, user0_.department_key as departme4_6_, user0_.email as email5_6_, user0_.mobile_phone as mobile_p6_6_, user0_.modify_time as modify_t7_6_, user0_.nickname as nickname8_6_, user0_.password as password9_6_, user0_.salt as salt10_6_, user0_.status as status11_6_, user0_.username as usernam12_6_ from user user0_ where user0_.email=?; parameters: ; named parameters: {email_0=mayun@alibaba.com}; transformer: org.hibernate.transform.CacheableResultTransformer@110f2 is null
2017-01-10 16:21:19.845 [main] DEBUG org.hibernate.cache.internal.StandardQueryCache  - Query results were not found in cache
Hibernate: select user0_.id as id1_6_, user0_.create_time as create_t2_6_, user0_.deleted as deleted3_6_, user0_.department_key as departme4_6_, user0_.email as email5_6_, user0_.mobile_phone as mobile_p6_6_, user0_.modify_time as modify_t7_6_, user0_.nickname as nickname8_6_, user0_.password as password9_6_, user0_.salt as salt10_6_, user0_.status as status11_6_, user0_.username as usernam12_6_ from user user0_ where user0_.email=?
Hibernate: select roles0_.user_id as user_id1_8_0_, roles0_.role_id as role_id2_8_0_, role1_.id as id1_4_1_, role1_.available as availabl2_4_1_, role1_.description as descript3_4_1_, role1_.role_key as role_key4_4_1_, role1_.role_value as role_val5_4_1_ from user_role roles0_ inner join role role1_ on roles0_.role_id=role1_.id where roles0_.user_id=?
Hibernate: select resourcepe0_.role_id as role_id4_5_0_, resourcepe0_.id as id1_5_0_, resourcepe0_.id as id1_5_1_, resourcepe0_.permission_ids as permissi2_5_1_, resourcepe0_.resource_id as resource3_5_1_, resourcepe0_.role_id as role_id4_5_1_ from role_resource_permission resourcepe0_ where resourcepe0_.role_id=?
2017-01-10 16:21:20.064 [main] DEBUG org.hibernate.cache.internal.StandardQueryCache  - Caching query results in region: org.hibernate.cache.internal.StandardQueryCache; timestamp=6078613420920832
2017-01-10 16:21:20.064 [main] DEBUG org.hibernate.cache.ehcache.internal.regions.EhcacheGeneralDataRegion  - key: sql: select user0_.id as id1_6_, user0_.create_time as create_t2_6_, user0_.deleted as deleted3_6_, user0_.department_key as departme4_6_, user0_.email as email5_6_, user0_.mobile_phone as mobile_p6_6_, user0_.modify_time as modify_t7_6_, user0_.nickname as nickname8_6_, user0_.password as password9_6_, user0_.salt as salt10_6_, user0_.status as status11_6_, user0_.username as usernam12_6_ from user user0_ where user0_.email=?; parameters: ; named parameters: {email_0=mayun@alibaba.com}; transformer: org.hibernate.transform.CacheableResultTransformer@110f2 value: [6078613420920832, 1]

// 查询出第一个对象,并缓存
com.teemo.entity.User@1a115fb4

2017-01-10 16:21:20.077 [main] DEBUG org.hibernate.cache.internal.StandardQueryCache  - Checking cached query results in region: org.hibernate.cache.internal.StandardQueryCache
2017-01-10 16:21:20.077 [main] DEBUG org.hibernate.cache.ehcache.internal.regions.EhcacheGeneralDataRegion  - key: sql: select user0_.id as id1_6_, user0_.create_time as create_t2_6_, user0_.deleted as deleted3_6_, user0_.department_key as departme4_6_, user0_.email as email5_6_, user0_.mobile_phone as mobile_p6_6_, user0_.modify_time as modify_t7_6_, user0_.nickname as nickname8_6_, user0_.password as password9_6_, user0_.salt as salt10_6_, user0_.status as status11_6_, user0_.username as usernam12_6_ from user user0_ where user0_.email=?; parameters: ; named parameters: {email_0=mayun@alibaba.com}; transformer: org.hibernate.transform.CacheableResultTransformer@110f2
2017-01-10 16:21:20.078 [main] DEBUG org.hibernate.cache.internal.StandardQueryCache  - Checking query spaces are up-to-date: [user]
2017-01-10 16:21:20.079 [main] DEBUG org.hibernate.cache.ehcache.internal.regions.EhcacheGeneralDataRegion  - key: user
2017-01-10 16:21:20.079 [main] DEBUG org.hibernate.cache.ehcache.internal.regions.EhcacheGeneralDataRegion  - Element for key user is null
2017-01-10 16:21:20.080 [main] DEBUG org.hibernate.cache.internal.StandardQueryCache  - Returning cached query results

// 根据SQL/HQL比对缓存key,命中
com.teemo.entity.User@5b867c31
  • 1
  • 2       原文出自:  https://blog.csdn.net/u011404265/article/details/54315248
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22

从结果中看出,在query中设置query.setCacheable(true);之后,所有被标记为可缓存的对象都会被缓存下来,所以第二次查询User时,直接命中二级缓存,没有发出SQL查询。

小结

我觉得,Hibernate的缓存模式应用场景太单一,对于通用的DAO或者底层查询方法来说,如果设置为query.setCacheable(true) 显然不太灵活,这样会缓存所有的调用该方法查询到的数据,如果不设置的话,又只能缓存get/load查询,结合自己的系统优化缓存模式还是很必要的,例如使用AOP进行Service切面缓存,这样就与DAO的ORM级别缓存分开了,相对更灵活。

查看评论

Hibernate开发框架

Hibernate是使用最多的ORMapping设计框架,在本课程之中将为读者完全的讲解Hibernate框架的原理以及各个实体组件的使用。官方QQ群:612148723。
  • 2017年01月02日 10:14

hibernate 缓存详解

  • 2009年07月11日 17:41
  • 655KB
  • 下载

Hibernate缓存深入详解 from ITEye

  • 2011年04月07日 16:15
  • 1.88MB
  • 下载

hibernate缓存详解

  • 2011年09月28日 20:50
  • 3.54MB
  • 下载

梳理hibernate篇-原理及缓存机制

Hibernate工作原理 现在我们知道了一个概念Hibernate Session,只有处于Session管理下的POJO才具有持久化操作能力。当应用程序对于处于Session管理下的...
  • u014586894
  • u014586894
  • 2016-06-11 00:52:42
  • 6484

Hibernate之缓存详解

一,缓存的概念 二,缓存的范围 三,Hibernate中的第一级缓存 1,get查询测试: 1>在同一个session中发出两次get查询 public void Query(){ Sessio...
  • an_2016
  • an_2016
  • 2016-08-03 21:57:00
  • 26887

hibernate的缓存和快照 (转载)

Hibernate我们已经学了四天,该讲的知识我们已经讲完,明天放假,后天练习一天就要结束hibernate的学习,有点不舍的,想来hibernate也不是传说中的那么难,在次将hibernate中三...
  • jing_44944
  • jing_44944
  • 2014-10-21 17:15:52
  • 1289

hibernate,hql与sql的缓存使用

1.在hibernate中createQuery执行hql查询的时候使用查询缓存:   getSession().createQuery(hql).setCacheable(true).setCa...
  • diquren
  • diquren
  • 2014-04-14 17:57:30
  • 2076

hibernate和mybatis缓存的对比

Mybatis缓存 分为1级缓存和2级缓存,2级缓存在sessionfactory中,1级缓存在session中。 session中的缓存在session连接关闭并被连接池回收时清...
  • Tidhy
  • Tidhy
  • 2017-06-02 16:01:49
  • 2112

浅谈hibernate的缓存和快照

最近开始学习hibernate框架,这是一个基于持久层的框架,是ORM思想的一种实现技术,主要解决的问题是如何把对象的数据直接保存到数据库和如何直接从数据库中取出一个对象,在学习session缓存和快...
  • xiaobai66073
  • xiaobai66073
  • 2016-11-29 15:05:52
  • 394
    个人资料
    等级:
    访问量: 498
    积分: 96
    排名: 142万+
    文章分类
    文章存档
    最新评论