`
chxiaowu
  • 浏览: 240020 次
  • 性别: Icon_minigender_1
  • 来自: 武汉
社区版块
存档分类
最新评论

Hibernate---在Hibernate中获取数据方式与缓存使用(转)

 
阅读更多

http://www.blogjava.net/pengpenglin/archive/2010/03/15/315440.html


Hibernate获取数据的方式有不同的几种,其与缓存结合使用的效果也不尽相同,而Hibernate中具体怎么使用缓存其实是我们很关心的一个问题,直接涉及到性能方面。   

缓存在Hibernate中主要有三个方面:一级缓存、二级缓存和查询缓存  

①一级缓存在Hibernate中对应的为session范围的缓存 ,也就是当session关闭时缓存即被清除,一级缓存在Hibernate中是不可配置的

②二级缓存在Hibernate中对应的为SessionFactory范围的缓存 , 通常来讲SessionFactory的生命周期和应用的生命周期相同,所以可以看成是进程缓存或集群缓存,二级缓存在Hibernate中是可以配置 的,可以通过class-cache配置类粒度级别的缓存(class-cache在class中数据发生任何变化的情况下自动更新),同时也可通过 collection-cache配置集合粒度级别的缓存(collection-cache仅在collection中增加了元素或者删除了元素的情况 下才自动更新,也就是当collection中元素发生值的变化的情况下它是不会自动更新的),跨session的缓存自然会带来并发的访问题,这个时候 相应的就要根据应用来设置缓存所采用的事务隔离级别,和数据库的事务隔离级别概念基本一样,没什么多介绍的

③查询缓存在Hibernate同样是可配置的
,默认是关闭的,可以通过设置cache.use_ query_cache为true来打开查询缓存。

根据缓存的通常实现策略,我们可以来理解Hibernate的这三种缓存,缓存的实现通过是通过key/value的Map方式来实现,在Hibernate的一级、二级和查询缓存也同样如此。 一 级、二级缓存使用的key均为po的主键ID,value即为po实例对象,查询缓存使用的则为查询的条件(hql转化而成的sql语句)、查询的参数、 查询的页数,value有两种情况,如果采用的是select po.property这样的方式那么value为整个结果集,如采用的是from这样的方式那么value为获取的结果集中各po对象的主键ID,这样 的作用很明显,节省内存。

简单介绍完Hibernate的缓存后,再结合Hibernate的获取数据方式来说明缓存的具体使用方式,在Hibernate中获取数据常用的方式主要有四种:Session.load、Session.get、Query.list、Query.iterator。

1、Session.load

在执行session.load时,Hibernate首先从当前 session的一级缓存中获取id对应的值,在获取不到的情况下,将根据该对象是否配置了二级缓存来做相应的处理,如配置了二级缓存,则从二级缓存中获 取id对应的值,如仍然获取不到则还需要根据是否配置了延迟加载来决定如何执行,如未配置延迟加载则从数据库中直接获取,在从数据库获取到数据的情况 下,Hibernate会相应的填充一级缓存和二级缓存,如配置了延迟加载则直接返回一个代理类,只有在触发代理类的调用时才进行数据库查询的操作。

备注 load方法过程:一级缓存 ---> 二级缓存 ----> DB访问 ---> 填充一级缓存[、二级缓存] / 返回一个代理类


在这样的情况下我们就可以看到,在session一直打开的情况下,要注意在适当的时候对一级缓存进行刷新操作,通常是在该对象具有单向关联维护的时候, 在Hibernate中可以使用象session.clear、session.evict的方式来强制刷新一级缓存。
二级缓存则在数据发生任何变化(新增、更新、删除)的情况下都会自动的被更新。

备注:由于一级缓存是位于物理内存空间的,毕竟大小有限。过多的对象缓存在这里会造成较大的压力。适当的时候刷新缓存除了可以保证数据库和内存的状态同步外,还可以移除不再用的对象,腾出空间来给后面的对象缓存使用。

2、Session.get

在执行Session.get时,和Session.load不同的就是在当从缓存中获取不到时,直接从数据库中获取id对应的值。

备注:load和get方法的另外一个区别就是:当对象在DB中找不到时,load会抛出异常,而get仅仅返回null

3、Query.list

在执行Query.list时,Hibernate的做法是首先检查是否配 置了查询缓存,如配置了则从查询缓存中查找key为查询语句+查询参数+分页条件的值,如获取不到则从数据库中进行获取,从数据库获取到后 Hibernate将会相应的填充一级、二级和查询缓存,如获取到的为直接的结果集,则直接返回,如获取到的为一堆id的值,则再根据id获取相应的值 (Session.load),最后形成结果集返回,可以看到,在这样的情况下,list也是有可能造成N次的查询的。 

查询缓存在数据发生任何变化的情况下都会被自动的清空。

备注:list()方法的SQL成本
 ①没有配置查询缓存或者缓存匹配不到时,发出一次SQL查询
 ②缓存的值为一组对象ID,则每个ID执行一次Session.load操作。视乎缓存对象是否还在会再发出0~N次SQL查询
 ③缓存的值为一组集合对象,则直接返回。此时不需要发出SQL查询

由此可见list()方法的SQL成本从0~N次不等,具体的次数和一、二级缓存的对象生命周期时间设置、SQL语句写法有关。如果采用select po.value写法,那么SQL成本最低(0),如果采用from po写法,那么SQL成本从0~N不等。

虽然表明看采用select po.value的写法好像会更加高效,但是考虑到对象的大小,但一次性读入时会造成大量的内存空间浪费。但是缓存ID又可能带来N次额外的查询消耗,应 该怎么办呢?最好的方法就是设置一、二级缓存的对象生命周期时间比查询缓存的生命周期长,这样不至于在Hibernate对每个ID执行 Session.load方法时实体缓存都过期而被清空了。

另外一个要注意的是:如果查询缓存引用的表在查询后被修改了,那么不管缓存的数据是否有变,该查询都会被清空而重新获取。因为Hibernate是靠比较每个表的修改时间和查询缓存的填入时间来判断表是否被修改了,它不会去判断具体的内容

4、Query.iterator

在执行 Query.iterator时,和Query.list的不同的在于从数据库获取的处理上,Query.iterator向数据库发起的是select id from这样的语句,也就是它是先获取符合查询条件的id,之后在进行iterator.next调用时才再次发起session.load的调用获取实 际的数据。

可见,在拥有二级缓存并且查询参数多变的情况下,Query.iterator会比Query.list更为高效。

备注:iterator的SQL成本
 ①最佳情况下,只有一次SQL查询(ID查询),其它的通过一、二级缓存可以得到
 ②最坏情况下,变成1+N次查询(ID查询 + 实体查询)

这四种获取数据的方式都各有适用的场合,要根据实际情况做相应的决定,最好的方式无疑就是打开show_sql选项看看执行的情况来做分析,系统结构上只 用保证这种调整是容易实现的就好了,在cache这个方面的调整自然是非常的容易,只需要调整配置文件里的设置,而查询的方式则可对外部进行屏蔽,这样要 根据实际情况调整也非常容易。

备注:关于list()和iterator()的查询成本比较

※没有配置查询缓存,或者缓存中没有对应的key :

   list():执行一次SQL查询全部取出
   iterator():执行一次SQL语句先取出符合条件的所有对象ID,在迭代期间通过Session.load方法查询(额外的0~N次查询)

※缓存值是一组对象ID:

   list():执行Session.load方法查询(额外的0~N次查询)

   iterator():执行Session.load方法查询(额外的0~N次查询)

※缓存值是一组集合:
   list():直接返回,没有SQL查询
   iterator():直接返回,没有SQL查询

可见最大的区别在于从数据库读取数据的地方,list虽然只有1次SQL查询,但它是直接 从物理数据文件中读取。而iterator虽然是1+N次查询,但后面的N次可能是从缓存中拿数据,所以SQL语句次数相同,兼之iterator只取 id,在缓存配置得当的情况下,iterator确实高效。但是如果缓存配置不当,那么iterator的后续next操作将不得不发出一次又一次的 SQL查询,反而大大比不上list。

从分页查询的情况来看,用iterator()的效率反而不及list():因为每页的对象的id都是不同的。iterator()使用Session.load时总是读取不到实体缓存(一级、二级缓存)的值,只能再发出一次SQL查询。


分享到:
评论

相关推荐

    hibernate-configuration-3.0.dtd、hibernate-mapping-3.0.dtd

    《深入理解Hibernate配置与映射:hibernate-configuration-3.0.dtd与hibernate-mapping-3.0.dtd解析》 在Java世界里,Hibernate作为一款强大的对象关系映射(ORM)框架,极大地简化了数据库操作。而`hibernate-...

    hibernate-release-4.1.4

    开发者通常会将这些JAR添加到项目类路径中,以便在项目中使用Hibernate的功能。而"使用帮助手册"则可能包括用户指南、API文档和示例代码,它们为开发者提供了详尽的指引,帮助理解Hibernate的工作原理、配置方法以及...

    hibernate-release-5.2.10

    2. **配置**:Hibernate的配置文件(如hibernate.cfg.xml)中需要设置数据库连接信息、方言、缓存策略等,这是使用Hibernate的第一步。 3. **会话工厂与会话**:SessionFactory是线程安全的,负责创建Session对象,...

    hibernate-release-5.0.7.Final的所有jar包

    Hibernate是Java领域中一款著名的对象关系映射(ORM)框架,它允许开发者使用面向对象的方式来操作数据库,极大地简化了数据库编程。在这个`hibernate-release-5.0.7.Final`版本中,包含了所有相关的jar包,为开发者...

    hibernate-extensions和Middlegen-Hibernate

    《hibernate-extensions与Middlegen-Hibernate:数据库到Java对象的自动化转换》 在Java的持久化层开发中,Hibernate作为一款强大的ORM(对象关系映射)框架,极大地简化了数据库操作。然而,手动编写实体类和映射...

    hibernate-memcached包

    一旦配置完成,Hibernate会在适当的时候自动将数据存入或从Memcached中获取,实现数据的高速缓存。 总的来说,`hibernate-memcached` 提供了一个方便的途径,让开发人员能够利用Memcached的强大缓存能力来提升基于...

    hibernate-core 核心jar包

    在Hibernate-Core中,主要包含以下几个关键模块和概念: 1. **Session接口**:它是Hibernate的主要工作接口,提供了对数据库的操作方法,如保存、更新、删除对象,以及执行SQL查询。Session管理了对象的状态,并...

    hibernate-5.2.15. 最新jar包

    8. **延迟加载(Lazy Loading)**:Hibernate可以实现属性或关联关系的延迟加载,只有在真正需要时才从数据库中获取数据,避免了内存占用过多。 9. **增强型实体**:Hibernate 5引入了代理实体(Enhanced Entity)...

    hibernate-jpa-2.1-api-1.0.0.final.jar.zip

    总的来说,`hibernate-jpa-2.1-api-1.0.0.final.jar`为开发者提供了丰富的JPA 2.1特性的实现,使得在Java项目中使用Hibernate进行数据库操作变得更加便捷和标准化。通过深入理解和熟练运用这个API,我们可以构建出...

    hibernate-memcached-1.1.0-sources.zip

    通过深入学习和理解源码,我们可以更好地掌握如何在项目中使用Memcached作为Hibernate的二级缓存,从而提升系统的数据访问性能。在实际开发中,根据项目需求,可能还需要考虑缓存的扩展性、并发控制以及失效策略等...

    hibernate-core-5.0.11.Final.jar

    Hibernate,作为Java领域中最著名的对象关系映射(ORM)框架之一,极大地简化了数据库操作,使得开发者能够以面向对象的方式处理数据。本文将重点探讨`hibernate-core-5.0.11.Final.jar`的核心源码,帮助读者深入...

    hibernate-release-5.0.7.Final.zip

    Hibernate,作为Java领域中的一个强大的对象关系映射(ORM)框架,极大地简化了数据库操作,使得开发者可以使用面向对象的方式处理数据库事务。在2016年,传智播客黑马程序员发布的Hibernate教程中,特别选用了...

    项目中使用 hibernate-memcached 做二级缓存

    本文将详述如何在项目中使用Hibernate与Memcached结合实现二级缓存,并探讨Memcached的基本原理和使用方法。 首先,我们需要理解什么是Hibernate的二级缓存。在Hibernate框架中,一级缓存是每个Session级别的,它...

    hibernate-release-5.0.0.Final(1).zip

    3. 优化查询:避免在HQL中使用子查询,尽量使用JOIN,合理设置缓存策略。 4. 谨慎使用事务:根据业务需求,正确设置事务隔离级别,避免死锁等问题。 总结,Hibernate 5.0.0.Final版本为Java开发者提供了更为强大的...

    hibernate-release-4.3.1.Final.zip

    Hibernate是Java开发中广泛使用的对象关系映射(ORM)工具,它允许开发者用面向对象的方式来操作数据库,从而简化了数据持久化的复杂性。这个版本可能是Hibernate的稳定版本,标记为"Final"意味着它经过充分测试,...

    hibernate-release-4.2.4.Final.zip

    6. **配置与使用**:在项目中使用Hibernate,首先需要在项目的类路径中添加相关的JAR包,然后配置Hibernate的主配置文件(hibernate.cfg.xml),指定数据库连接信息和实体类映射。接着,通过SessionFactory创建...

    hibernate-release-5.3.2.Final

    1. 性能优化:5.3.2.Final版本在性能方面进行了大量优化,包括查询缓存、二级缓存策略以及连接池管理等,提高了数据处理速度和资源利用效率。 2. JPA 2.2支持:该版本全面支持Java Persistence API 2.2规范,引入了...

    hibernate-release-4.3.0.Beta2 lib

    Hibernate,作为一个强大的对象关系映射(ORM)框架,是Java开发中的重要工具,它极大地简化了数据库操作,使得开发者能够用面向对象的方式来处理数据。本篇文章将深入探讨 Hibernate 4.3.0 Beta2 版本中的库文件,...

    hibernate-validator-5.2.4.Final.jar

    除了运行时验证,Hibernate Validator 还提供了一套元数据 API,允许在编译时或者运行时通过反射获取验证信息。这对于构建工具或者框架集成非常有用,可以提前发现验证错误,而不是等到运行时才暴露问题。 四、与 ...

    hibernate-annotations-3.4.0.GA

    Hibernate是Java领域中广泛应用的对象关系映射(ORM)框架,它极大地简化了数据库操作,使得开发者可以使用面向对象的方式来处理数据。而Hibernate Annotations是Hibernate框架的一个重要组成部分,它引入了基于注解...

Global site tag (gtag.js) - Google Analytics