hibernate 的缓存使用问题

问题描述

问题描述见:在测试Hibernate二级缓存的时候把ehcache.xml和hibernate.cfg.xml里的相关二级缓存的配置 都删掉 ,直接在hbm.xml中配置 <cache usage= "read-write " /> ,发现查询结果看起来仍是通过缓存来查询的 因为sql没有打印两次package com.vavi.test;import org.hibernate.Session;import com.vavi.dao.HibernateSessionFactory;import com.vavi.pojo.Tuser;public class Test {public static void main(String[] args) {Session sess = HibernateSessionFactory.getCurrentSession();Tuser user_load = (Tuser) sess.load(com.vavi.pojo.Tuser.class,new Long(1));System.out.println(user_load.getName()); sess.close(); sess = HibernateSessionFactory.getCurrentSession();Tuser user_get = (Tuser) sess.get(com.vavi.pojo.Tuser.class,new Long(1));System.out.println(user_get.getName());sess.close();}}HibernateSessionFactory 是MyEclipse 生成的 问题补充:package com.vavi.test;/** * 结论:Session级别的缓存 仅在当前session 生命期内有效 * 一旦该session关闭 ,再次查询时仍需要访问数据库 */import org.hibernate.Session;import com.vavi.dao.HibernateSessionFactory;import com.vavi.pojo.Tuser;public class Test_SessionClose {/** * @param args */public static void main(String[] args) {// TODO Auto-generated method stubSession sess = HibernateSessionFactory.getCurrentSession();Tuser user_load =(Tuser) sess.load(com.vavi.pojo.Tuser.class, new Long(1));System.out.println(user_load.getName());sess.close();sess = HibernateSessionFactory.getCurrentSession();Tuser user_get =(Tuser) sess.get(com.vavi.pojo.Tuser.class, new Long(1));System.out.println(user_get.getName());sess.close();}}这段代码跟上面的一样 唯一 不同的地方就是 不在 Tuser.hbm.xml 加上 <cache usage="read-write" />这时候打印的结果是 :Hibernate: select tuser0_.ID as ID0_, tuser0_.NAME as NAME0_0_, tuser0_.AGE as AGE0_0_ from GHJ.TUSER tuser0_ where tuser0_.ID=?ghjHibernate: select tuser0_.ID as ID0_, tuser0_.NAME as NAME0_0_, tuser0_.AGE as AGE0_0_ from GHJ.TUSER tuser0_ where tuser0_.ID=?ghj说明session cache 还是失效了的 按照您的说法 我打印了下 System.out.println("session:"+sess);这两个程序(加不加 <cache usage="read-write" /> )都是 session:org.hibernate.impl.SessionImpl(<closed>)根据这个打印结果并不能看出什么 所以关键是 这段话 <cache usage="read-write" />不太清楚 他到底有什么作用 应该不是 一级缓存 二级缓存 或 查询缓存 最后谢谢您的解答 ^^问题补充:多谢gotothework的 回答你说的这几种策略我也知道但是关键是加上这段话后 <cache usage="read-write" /> 不需要访问数据库 就可以直接出现结果了 (详细描述见上)而我认为 这个查询结果不是 一级缓存 二级缓存 或 查询缓存 里面的内容 但是如果不是 hibernate 又是如何管理这部分缓存的 抑或还是我的理解有误?问题补充:To gotothework :在调用sess.close()这个方法以前,一级缓存是一直有效的.所以应该是由一级缓存里调用出来的. 当你查询时,会首先从一级缓存中寻找,如果查找不到,还会从二级缓存中寻找,如果还未找到,就会从数据库中查询.我明白你见我第二个问题补充,现在问题是 其他配置(二级缓存 查询缓存 都不配置),仅在Tuser.hbm.xml 加上 <cache usage="read-write" /> 打印结果表明: 第二次查询结果 没有访问数据库 就直接返回结果了 问题补充: To gotothework : 在您说的这种情况下hibernate是使用哪种缓存呢? 一级缓存?但是如果同样的程序不在 Tuser.hbm.xml 加上 <cache usage="read-write" /> 仍是需要先后访问两次数据库的 所以这段 <cache usage="read-write" /> 代码作用很诡异难道加了这段话就保存了一级缓存的数据?您说的openSession()我试了下 同时加上了 sess.contains(user_load) 和hashCode() 这个方法 package com.vavi.dao;import org.hibernate.Session;import org.hibernate.SessionFactory;import org.hibernate.cfg.Configuration;//import com.vavi.dao.HibernateSessionFactory;import com.vavi.pojo.Tuser;public class SFTest {public static void main(String[] args) {SessionFactory sf = new Configuration().configure().buildSessionFactory();Session sess = sf.openSession();System.out.println(sess.hashCode());Tuser user_load = (Tuser) sess.load(com.vavi.pojo.Tuser.class,new Long(1));System.out.println("sess.contains user_load? "+sess.contains(user_load));System.out.println(user_load.getName()); sess.close(); System.out.println("sess.contains user_load? "+sess.contains(user_load)); sess =sf.openSession(); System.out.println(sess.hashCode()); Tuser user_get = (Tuser) sess.get(com.vavi.pojo.Tuser.class,new Long(1));System.out.println("sess.contains user_load? "+sess.contains(user_load));System.out.println("sess.contains user_get? "+sess.contains(user_get));System.out.println(user_get.getName());sess.close();System.out.println("sess.contains user_get? "+sess.contains(user_get));}}打印结果如下:31966667sess.contains user_load? trueHibernate: select tuser0_.ID as ID0_, tuser0_.NAME as NAME0_0_, tuser0_.AGE as AGE0_0_ from GHJ.TUSER tuser0_ where tuser0_.ID=?ghjsess.contains user_load? false22375698sess.contains user_load? falsesess.contains user_get? trueghjsess.contains user_get? false所以这个现象就比较诡异了发现sess关闭后,sess.contains(user_load)返回值是false的。但是仍未查询数据库就获得结果了问题补充:哈哈 问题搞定 忘了hibernate 是默认启动二级缓存 以及使用 Cache provider: org.hibernate.cache.EhCacheProvider.我上述的问题现象其实还是使用Hibernate的 二级缓存的 [main] (SettingsFactory.java:209) - Second-level cache: enabled INFO [main] (SettingsFactory.java:213) - Query cache: disabled INFO [main] (SettingsFactory.java:321) - Cache provider: org.hibernate.cache.EhCacheProvider INFO [main] (SettingsFactory.java:228) - Optimize cache for minimal puts: disabled INFO [main] (SettingsFactory.java:237) - Structured second-level cache entries: disabled总结:1、使用二级缓存的话 仅仅必须在 Tuser.hbm.xml 加上 <cache usage="read-write" /> 其他设置使用的是Hibernate 里面jar包的默认配置文件 当然如果需要高级应用,那就需要自定义配置文件了2、对于Hibernate,遇到不明白的问题,建议加上<property name="generate_statistics">true</property> 并打印debug级别日志3、Session sess = HibernateSessionFactory.getCurrentSession(); 仍是获得新的session 实例的 同时 一级缓存(Session Cache)是在session.close() 调用后就失效的,跟当前没关系 (不知道理解有没有问题)4、没有莫名其妙的问题,想起老大对我说的一句公告。 哈哈 ,这就是我中秋节的礼物了 ^^

解决方案

刚才是我理解错你的意思了,Session sess = HibernateSessionFactory.getCurrentSession();如果你这么去调用,将会把当前线程与Session绑定,而且在线程结束时,Hibernate会自动的关闭这个与线程绑定的Session,不需要你手动关闭.即使你手动的关闭也不会起作用,因为你当前的线程没有结束.所以,当你第二次调用Session sess = HibernateSessionFactory.getCurrentSession();这个方法的时候,其实获得的Session与第一次获得的是同一个,这就是为什么第二次直接返回的结果,而没有去数据库中查询.这里你可以试一下openSession(),他是每次都创建一个新的Session实例.
解决方案二:
Hibernate的一级缓存是必须使用的,既然你删除了二级缓存,那这里就应该用到了一级缓存,一级缓存是由Session来维护的,也就是说,在你Session开启的情况下,你的一级缓存一直有效,只有在你调用了Session的close()方法后,Session所维护的一级缓存才会失效,从楼主的代码来看 public static void main(String[] args) { Session sess = HibernateSessionFactory.getCurrentSession(); Tuser user_load = (Tuser) sess.load(com.vavi.pojo.Tuser.class, new Long(1)); System.out.println(user_load.getName()); sess.close(); sess = HibernateSessionFactory.getCurrentSession(); Tuser user_get = (Tuser) sess.get(com.vavi.pojo.Tuser.class, new Long(1)); System.out.println(user_get.getName()); sess.close(); } 在调用sess.close()这个方法以前,一级缓存是一直有效的.所以应该是由一级缓存里调用出来的.当你查询时,会首先从一级缓存中寻找,如果查找不到,还会从二级缓存中寻找,如果还未找到,就会从数据库中查询.不知道我这次说的对楼主是否有帮助,如果不明,非常高兴与你讨论
解决方案三:
这里的usage是缓存的策略,你可以根据你的需要来设置缓存策略,总共右种transactional、 read-write、 nonstrict-read-write或 read-only。只读缓存(Strategy: read only) 如果你的应用程序只需读取一个持久化类的实例,而无需对其修改, 那么就可以对其进行只读 缓存。这是最简单,也是实用性最好的方法。甚至在集群中,它也能完美地运作。读/写缓存(Strategy: read/write) 如果应用程序需要更新数据,那么使用读/写缓存 比较合适。 如果应用程序要求“序列化事务”的隔离级别(serializable transaction isolation level),那么就决不能使用这种缓存策略。 如果在JTA环境中使用缓存,你必须指定hibernate.transaction.manager_lookup_class属性的值, 通过它,Hibernate才能知道该应用程序中JTA的TransactionManager的具体策略。 在其它环境中,你必须保证在Session.close()、或Session.disconnect()调用前, 整个事务已经结束。 如果你想在集群环境中使用此策略,你必须保证底层的缓存实现支持锁定(locking)。Hibernate内置的缓存策略并不支持锁定功能。非严格读/写缓存(Strategy: nonstrict read/write) 如果应用程序只偶尔需要更新数据(也就是说,两个事务同时更新同一记录的情况很不常见),也不需要十分严格的事务隔离, 那么比较适合使用非严格读/写缓存策略。如果在JTA环境中使用该策略, 你必须为其指定hibernate.transaction.manager_lookup_class属性的值, 在其它环境中,你必须保证在Session.close()、或Session.disconnect()调用前, 整个事务已经结束。 事务缓存(transactional) Hibernate的事务缓存策略提供了全事务的缓存支持, 例如对JBoss TreeCache的支持。这样的缓存只能用于JTA环境中,你必须指定 为其hibernate.transaction.manager_lookup_class属性。 大体就是这样,希望对楼主有所帮助
解决方案四:
配置文件都删了应该不会启用的,可能是读到一级缓存的内容了,虽然sess.colse()会清空一级缓存,你再测一下吧,把session打印出来看一下,看一下里面有没有Tuser bean,有的话就是一级缓存了,如下:public class Test { public static void main(String[] args) { Session sess = HibernateSessionFactory.getCurrentSession(); Tuser user_load = (Tuser) sess.load(com.vavi.pojo.Tuser.class, new Long(1)); System.out.println(user_load.getName()); sess.close(); System.out.println("session:"+sess); sess = HibernateSessionFactory.getCurrentSession(); Tuser user_get = (Tuser) sess.get(com.vavi.pojo.Tuser.class, new Long(1)); System.out.println(user_get.getName()); sess.close(); } }

时间: 2024-08-02 20:48:13

hibernate 的缓存使用问题的相关文章

Hibernate的缓存机制介绍

缓存 缓存是介于应用程序和物理数据源之间,其作用是为了降低应用程序对物理数据源访问的频次,从而提高了应用的运行性能.缓存内的数据是对物理数据源中的数据的复制,应用程序在运行时从缓存读写数据,在特定的时刻或事件会同步缓存和物理数据源的数据. 缓存的介质一般是内存,所以读写速度很快.但如果缓存中存放的数据量非常大时,也会用硬盘作为缓存介质.缓存的实现不仅仅要考虑存储的介质,还要考虑到管理缓存的并发访问和缓存数据的生命周期. Hibernate的缓存包括Session的缓存和SessionFactor

java模拟hibernate一级缓存示例分享_java

纯Java代码模拟Hibernate一级缓存原理,简单易懂. 复制代码 代码如下: import java.util.ArrayList;import java.util.HashMap;import java.util.List;import java.util.Map; public class LevelOneCache { //这个对象就是用来模拟hibernate一级缓存的 private static Map<Integer, Student> stus=new HashMap&l

javaweb-关于hibernate一级缓存问题。

问题描述 关于hibernate一级缓存问题. hibernate的list查询会向一级缓存里面放入数据,但是下次取数据的时候,却不会再一级缓存里面取 ,怎样可以令到list查询到一级缓存里面取数据? 解决方案 所谓的下一次是在同一个Session中还是在不同的Session中, 在同一个Session中当然可以获取得到 在不同的Session中当然不能获取了(因为另一个Session已经关闭了)

javaweb-关于hibernate一级缓存问题

问题描述 关于hibernate一级缓存问题 Team team = (Team) meaulInter.executeQueryById(Team.class, 1); System.out.println(team.getName()); Team team2 = (Team) meaulInter.executeQueryById(Team.class, 1); System.out.println(team2.getName()); 这段代码中,meaulInter类里面有一个查询方法,

hibernate的缓存不刷新问题

问题描述 hibernate的缓存不刷新问题 sql = @" select * from UserInfo ui where ui.IsBusiness<>1 and ui.Status=0 and ui.islogin<>2 and ui.[Unit] like :queryname"; ISQLQuery query = session.CreateSQLQuery(sql).AddEntity(typeof(UserInfo)); query.SetSt

缓存机制-hibernate二级缓存问题。

问题描述 hibernate二级缓存问题. 我把 List teams = meaulInter.executeQuery(""from Team""); 这个查询出来的结果放到了二级缓存里面.然后这个Team对象 跟 一个 Page 对象 是1对多关系,因此,当我要引出Team对象对应的多方Page对象的属性的时候,会向数据库发出查询语句,我想把查询的结果放到缓存里面我该怎么做,才会令到懒加载的时候能从缓存中取出? 解决方案 参考:http://www.docin

如果项目已有spring缓存,还需要hibernate二级缓存么

问题描述 如果项目已有spring缓存,还需要hibernate二级缓存么 如果项目已有spring缓存,还需要hibernate二级缓存么,RT 解决方案 Spring环境下Hibernate二级缓存的应用---------------------- 解决方案二: 不是太清楚,大家一起学习

hibernate二级缓存的配置

问题描述 写了一个hibernate二级缓存的例子,从日志中看,似乎二级缓存已经启用,但在执行效果看,没有到二级缓存中查找数据.忘各位高手们帮帮小弟配置文件如下:hibernate.cfg.xml<?xmlversion="1.0"encoding="UTF-8"?><!DOCTYPEhibernate-configurationPUBLIC"-//Hibernate/HibernateConfigurationDTD3.0//EN&qu

hibernate的缓存配置问题

问题描述 hibernate的缓存配置问题 hibernate的缓存已经设置好了....经过测试没有问题... <defaultCache maxElementsInMemory="10000" eternal="false" timeToIdleSeconds="120" timeToLiveSeconds="120" overflowToDisk="true" diskPersistent=&qu