`
liangguanhui
  • 浏览: 112883 次
  • 性别: Icon_minigender_1
社区版块
存档分类
最新评论

我遇到的Hibernate使用查询缓存的一个问题

阅读更多
这两天在优化人事系统的性能,其中一个工作就是为系统应用Hibernate的缓存。Hibernate有几个缓存:一级缓存、二级缓存、查询缓存。其中我在实现查询缓存的时候出了一些毛病,弄了我两天。
事情是这样的,系统有一大堆代码表,按照一般的原则,代码表当然是缓存起来用。以其中一个表为例:

/**
 * 代码抽象类
 */
@MappedSuperclass
public abstract class Code implements Serializable {
  
  private static final long serialVersionUID = 8945711128421853350L;
  
  protected long id;
  
  protected String code;
  
  protected String name;
  
  public Code() {
    super();
  }
  
  @Id
  @GeneratedValue(strategy=GenerationType.AUTO)
  public long getId() {
    return id;
  }

  其它getter、setter....
  
}

/**
 * 工资类别代码
 */
@Entity
@Table(name="C_SalaryType")
@Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
public class SalaryType extends Code {
  
  public SalaryType() {
  }
  
}

/**
 * 工资级别码
 */
@Entity
@Table(name="C_SalaryLevel")
@Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
public class SalaryLevel extends Code {
  
  public SalaryLevel() {
  }
  
}


可以看到我这里的所有代码都继承一个Code的base class。在选择代码缓存类型的时候,考虑到代码不是经常修改,所以选择菲严格读写,即NONSTRICT_READ_WRITE。
(开始的时候,我把“@Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)”这句放到Code类里面,发现并不起作用,必须要把它放到具体的类里面才能起作用。不过这是题外话。)

然后重新部署应用,登陆、查看基本信息,问题来了:第二次或者之后查看基本信息,载入需要很长时间,凭感觉比不用缓存的时候还要慢。什么原因呢?查看了一下日志,不看不知道,一看吓一条,系统输出n条下面的sql语句:
Hibernate:
  select
    salarytype0_.id as id77_0_,
    salarytype0_.code as code77_0_,
    salarytype0_.name as name77_0_
  from
    C_SalaryType salarytype0_
  where
    salarytype0_.id in (
      ?, ?, ?, ?, ?, ?, ?, ?
    )
怎么回事?
开始我还以为是查询基本信息表的时候有问题,不过经过查证并且使用调试(netbeans的webapp调试做得还可以)终于查到是查询这个代码表“From SalaryLevel”的时候出事。
我大概数了一下,貌似是使用这种方法重新遍历了一遍alarytype的所有数据,查询缓存不起作用。
不过其它代码类倒是没有这个问题,怎么回事?我认真查了一下代码,发现除了表名、类名不同之外,所有代码的确是一样的,既然一样,何解效果不同呢?

我又尝试改变缓存类型,结果还是一样。怪了,到底怎么回事?

第二天,我还是没有什么头绪,难道是hibernate的bug?不过应该不大可能,其它代码都没什么问题,就几个代码有这种问题。后来突发奇想,打开了org.hibernate.cache包的debug输出(之前是warn输出),输出如下:
junit测试代码是
  public void testGetCodeList() {
    for (int i = 0; i < 2; i++) {
      System.out.println("\n\nTimes: " + (i + 1));
      service.getCodeList(SalaryType.class);
    }
  }

测试结果是


//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
SimpleContext: bind [java:comp/env/jdbc/hsDB]
SimpleContext: lookup [java:comp/env/jdbc/hsDB]
12:39:03,031 DEBUG org.hibernate.cache.CacheFactory:39 - instantiating cache region: com.dcampus.hr3.domain.code.JobType usage strategy: nonstrict-read-write
12:39:03,031 WARN org.hibernate.cache.EhCacheProvider:86 - Could not find configuration [com.dcampus.hr3.domain.code.JobType]; using defaults.
12:39:03,046 DEBUG org.hibernate.cache.EhCacheProvider:89 - started EHCache region: com.dcampus.hr3.domain.code.JobType
(一大堆重复上面三句)
12:39:05,015 INFO org.hibernate.cache.UpdateTimestampsCache:41 - starting update timestamps cache at region: org.hibernate.cache.UpdateTimestampsCache
12:39:05,015 WARN org.hibernate.cache.EhCacheProvider:86 - Could not find configuration [org.hibernate.cache.UpdateTimestampsCache]; using defaults.
12:39:05,015 DEBUG org.hibernate.cache.EhCacheProvider:89 - started EHCache region: org.hibernate.cache.UpdateTimestampsCache
12:39:05,031 INFO org.hibernate.cache.StandardQueryCache:52 - starting query cache at region: org.hibernate.cache.StandardQueryCache
12:39:05,031 WARN org.hibernate.cache.EhCacheProvider:86 - Could not find configuration [org.hibernate.cache.StandardQueryCache]; using defaults.
12:39:05,031 DEBUG org.hibernate.cache.EhCacheProvider:89 - started EHCache region: org.hibernate.cache.StandardQueryCache


Times: 1
12:39:05,781 DEBUG org.hibernate.cache.StandardQueryCache:102 - checking cached query results in region: org.hibernate.cache.StandardQueryCache
12:39:05,781 DEBUG org.hibernate.cache.EhCache:68 - key: sql: select salarytype0_.id as id77_, salarytype0_.code as code77_, salarytype0_.name as name77_ from C_SalaryType salarytype0_; parameters: ; named parameters: {}
12:39:05,781 DEBUG org.hibernate.cache.EhCache:77 - Element for sql: select salarytype0_.id as id77_, salarytype0_.code as code77_, salarytype0_.name as name77_ from C_SalaryType salarytype0_; parameters: ; named parameters: {} is null
12:39:05,781 DEBUG org.hibernate.cache.StandardQueryCache:107 - query results were not found in cache
Hibernate:
  select
    salarytype0_.id as id77_,
    salarytype0_.code as code77_,
    salarytype0_.name as name77_
  from
    C_SalaryType salarytype0_
12:39:06,015 DEBUG org.hibernate.cache.NonstrictReadWriteCache:71 - Caching: com.dcampus.hr3.domain.code.SalaryType#1
12:39:06,015 DEBUG org.hibernate.cache.NonstrictReadWriteCache:71 - Caching: com.dcampus.hr3.domain.code.SalaryType#2
12:39:06,015 DEBUG org.hibernate.cache.NonstrictReadWriteCache:71 - Caching: com.dcampus.hr3.domain.code.SalaryType#3
(重复至1546)
12:39:07,312 DEBUG org.hibernate.cache.StandardQueryCache:73 - caching query results in region: org.hibernate.cache.StandardQueryCache; timestamp=4887704147902464


Times: 2
12:39:07,328 DEBUG org.hibernate.cache.StandardQueryCache:102 - checking cached query results in region: org.hibernate.cache.StandardQueryCache
12:39:07,328 DEBUG org.hibernate.cache.EhCache:68 - key: sql: select salarytype0_.id as id77_, salarytype0_.code as code77_, salarytype0_.name as name77_ from C_SalaryType salarytype0_; parameters: ; named parameters: {}
12:39:07,328 DEBUG org.hibernate.cache.StandardQueryCache:156 - Checking query spaces for up-to-dateness: [C_SalaryType]
12:39:07,328 DEBUG org.hibernate.cache.EhCache:68 - key: C_SalaryType
12:39:07,328 DEBUG org.hibernate.cache.EhCache:77 - Element for C_SalaryType is null
12:39:07,328 DEBUG org.hibernate.cache.StandardQueryCache:117 - returning cached query results
12:39:07,343 DEBUG org.hibernate.cache.NonstrictReadWriteCache:41 - Cache lookup: com.dcampus.hr3.domain.code.SalaryType#1
12:39:07,343 DEBUG org.hibernate.cache.EhCache:68 - key: com.dcampus.hr3.domain.code.SalaryType#1
12:39:07,343 DEBUG org.hibernate.cache.EhCache:77 - Element for com.dcampus.hr3.domain.code.SalaryType#1 is null
12:39:07,343 DEBUG org.hibernate.cache.NonstrictReadWriteCache:49 - Cache miss
12:39:07,343 DEBUG org.hibernate.cache.EhCache:68 - key: com.dcampus.hr3.domain.code.SalaryType#2
12:39:07,343 DEBUG org.hibernate.cache.EhCache:77 - Element for com.dcampus.hr3.domain.code.SalaryType#2 is null
12:39:07,343 DEBUG org.hibernate.cache.EhCache:68 - key: com.dcampus.hr3.domain.code.SalaryType#3
12:39:07,343 DEBUG org.hibernate.cache.EhCache:77 - Element for com.dcampus.hr3.domain.code.SalaryType#3 is null
12:39:07,343 DEBUG org.hibernate.cache.EhCache:68 - key: com.dcampus.hr3.domain.code.SalaryType#4
12:39:07,343 DEBUG org.hibernate.cache.EhCache:77 - Element for com.dcampus.hr3.domain.code.SalaryType#4 is null
12:39:07,343 DEBUG org.hibernate.cache.EhCache:68 - key: com.dcampus.hr3.domain.code.SalaryType#5
12:39:07,343 DEBUG org.hibernate.cache.EhCache:77 - Element for com.dcampus.hr3.domain.code.SalaryType#5 is null
12:39:07,359 DEBUG org.hibernate.cache.EhCache:68 - key: com.dcampus.hr3.domain.code.SalaryType#6
12:39:07,359 DEBUG org.hibernate.cache.EhCache:77 - Element for com.dcampus.hr3.domain.code.SalaryType#6 is null
12:39:07,359 DEBUG org.hibernate.cache.EhCache:68 - key: com.dcampus.hr3.domain.code.SalaryType#7
12:39:07,359 DEBUG org.hibernate.cache.EhCache:77 - Element for com.dcampus.hr3.domain.code.SalaryType#7 is null
12:39:07,359 DEBUG org.hibernate.cache.EhCache:68 - key: com.dcampus.hr3.domain.code.SalaryType#8
12:39:07,359 DEBUG org.hibernate.cache.EhCache:77 - Element for com.dcampus.hr3.domain.code.SalaryType#8 is null
Hibernate:
  select
    salarytype0_.id as id77_0_,
    salarytype0_.code as code77_0_,
    salarytype0_.name as name77_0_
  from
    C_SalaryType salarytype0_
  where
    salarytype0_.id in (
      ?, ?, ?, ?, ?, ?, ?, ?
    )
(重复上面Time2后面的内容至1546)

////////////////////// end ////////////////////////////////////////////////////////////////////

从上面可以看到,原来是每次查询都不能击中缓存。怎么会击不中?我看到1546,突然想起我的ehcache的配置是默认1000个

<ehcache>
  <defaultCache
      maxElementsInMemory="1000"
      timeToIdleSeconds="600"
      timeToLiveSeconds="1800"
      eternal="false"
      overflowToDisk="false"
      diskPersistent="false"
      memoryStoreEvictionPolicy="LRU"
      />
</ehcache>

而那些代码的数目超过一千个,所以每次查询都不能命中。把1000改为10000,测试通过。
分享到:
评论

相关推荐

    Hibernate 使用缓存时,数据同步问题

    #### Hibernate缓存机制概述 Hibernate提供了两种缓存级别:一级缓存和二级缓存。 - **一级缓存**:存在于Session范围内,用于存储实体的实例和状态。当一个实体被加载到Session时,其状态会保存在一级缓存中,...

    Hibernate缓存

    然而,由于查询缓存可能遇到数据不一致的问题,因此在使用时需要谨慎,尤其是在高并发场景下。 4-1 分布式缓存: 在大型分布式系统中,二级缓存可能需要跨服务器共享。此时,可以配置为分布式缓存,确保多个服务器...

    Hibernate中二级缓存ehcache缓存案例

    ehcache是Hibernate官方推荐的二级缓存实现,它是一个高性能、轻量级的缓存框架。使用ehcache可以将频繁访问的数据存储在内存中,避免了频繁的数据库交互,从而提高了系统的响应速度。ehcache具有可扩展性,支持磁盘...

    菜鸟快速运行第一个hibernate

    ”表达了这个教程的目标是避免新手在学习过程中遇到常见问题,确保他们能够顺利地完成第一个Hibernate应用的搭建和运行。 **知识点详解** 1. **Hibernate简介**:Hibernate是一个开源的ORM框架,它将Java对象与...

    springMvc+Hibernate实现的一个问题管理系统

    本文将深入探讨如何使用SpringMvc和Hibernate这两个强大的框架,构建一个功能完善的问题管理系统。首先,我们来看看SpringMvc和Hibernate的核心概念及其在项目中的作用。 SpringMvc是Spring框架的一个模块,专门...

    hibernate N+1问题解决办法

    在Java开发中,使用Hibernate作为ORM框架时,我们可能会遇到一个性能上的问题,那就是著名的“N+1查询问题”。此问题源于不恰当的数据加载策略,可能导致数据库查询效率低下,尤其在大数据量的情况下,会严重影响...

    hibernate5.2.7-src源码

    Hibernate是一个开源的ORM框架,它为Java开发人员提供了在Java应用程序中操作数据库的强大工具。通过将Java类与数据库表之间的映射关系进行管理,Hibernate简化了数据访问层的代码编写,使得开发者能够更专注于业务...

    Hibernate查询映射试验

    在这个“Hibernate查询映射试验”项目中,你可能会遇到如何配置SessionFactory、如何创建和执行HQL/Criteria查询、如何处理关联映射(如一对一、一对多、多对多)、如何使用事务管理等实践环节。理解并熟练掌握这些...

    hibernate-3.2源代码

    Hibernate是一个开源的对象关系映射(ORM)框架,它极大地简化了Java应用程序与数据库之间的交互。在Hibernate 3.2版本中,开发者们能够更深入地理解其内部机制,从而提高开发效率和应用性能。本篇文章将详细解析...

    孙卫琴hibernate source code2

    在IT领域,Hibernate作为一个强大的对象关系映射(ORM)框架,极大地简化了Java开发者与数据库之间的交互。孙卫琴老师的“Hibernate源码解析”系列深入剖析了Hibernate的内部机制,帮助开发者更好地理解和运用这个...

    spring,hibernate做的用户管理系统源码,带登陆,带分页功能

    这是一个基于Java技术栈,利用Spring和Hibernate框架构建的用户管理系统源码项目,具有登录功能以及分页展示数据的特性。让我们深入探讨这个系统的几个关键知识点。 首先,Spring框架是整个应用的核心,它提供了...

    Hibernate源码解析(一)

    Hibernate是由 Gavin King 创建的一个开源项目,它提供了一种在Java应用中持久化对象到关系数据库的解决方案。通过ORM,Hibernate将对象模型与关系数据库模型进行映射,使得开发人员可以使用面向对象的方式来处理...

    hibernate3.5.0官方手册

    而对于有经验的开发者,它则是一个不可或缺的参考工具,帮助解决在实际项目中遇到的问题。 由于这份手册是HTML格式,用户可以直接在浏览器中查看,方便快捷。如果遇到显示乱码的问题,只需将浏览器的编码设置为...

    hibernate源码release-4.1.4.Final版

    包括但不限于:合理使用缓存,避免N+1查询问题,使用批处理更新,选择合适的主键生成策略,以及优化HQL和SQL查询等。 通过深入学习Hibernate 4.1.4.Final的源码,我们可以更好地理解其设计思想,提升我们的编程技巧...

    Hibernate Reference官方文档实践日记一

    【压缩包子文件的文件名称列表】:“Hellohibernate”可能是作者创建的一个示例项目,用于展示Hibernate的基本用法。这个项目可能包括了配置文件(如hibernate.cfg.xml)、实体类、数据访问对象(DAO)以及相关的...

    Hibernate 手册 第一章 Hibernate入门

    在实际使用中,可能会遇到缓存问题、性能瓶颈等。例如,第一加载实体时可能会进行全表扫描,可通过二级缓存、预加载、批处理等方式优化。此外,合理选择访问策略、避免N+1查询等问题也对性能有很大影响。 总结,...

    Hibernate Developer Guide

    Hibernate是一个流行的Java对象关系映射(ORM)框架,它简化了基于Java的应用程序与数据库之间的交互。该文档《Hibernate Developer...它可以帮助开发者有效地使用Hibernate进行数据库交互,并解决可能遇到的复杂问题。

Global site tag (gtag.js) - Google Analytics