hibernate 的缓存使用问题

悬赏:5 发布时间:2008-09-13 提问人:vavi (初级程序员)

<script type="text/javascript"></script>
 
< > 猎头职位: 
  <script type="text/javascript"></script>

问题描述见:
在测试Hibernate二级缓存的时候
把ehcache.xml和hibernate.cfg.xml里的相关二级缓存的配置  都删掉 ,
直接在hbm.xml中配置 <cache  usage= "read-write "  /> ,
发现查询结果看起来仍是通过缓存来查询的
因为sql没有打印两次

Java代码

hibernate 的缓存使用问题 转_公告


这段代码跟上面的一样

1. package
2.   
3. import
4.   
5. import
6. import
7.   
8. public class
9. public static void
10.            
11.         Session sess = HibernateSessionFactory.getCurrentSession();   
12. class,    
13. new Long(1));    
14.         System.out.println(user_load.getName());   
15.          sess.close();   
16.                    
17.          sess = HibernateSessionFactory.getCurrentSession();   
18. class,    
19. new Long(1));    
20.         System.out.println(user_get.getName());   
21.   
22.         sess.close();   
23.     }   
24.   
25. }  
 
 
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 stub 
 
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(); 
 
} 
 

}


唯一 不同的地方就是 不在 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=?


ghj


Hibernate: 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)); 
 
} 
 

} 
 
打印结果如下: 
 
31966667 
 
sess.contains user_load? true 
 
Hibernate: select tuser0_.ID as ID0_, tuser0_.NAME as NAME0_0_, tuser0_.AGE as AGE0_0_ from GHJ.TUSER tuser0_ where tuser0_.ID=? 
 
ghj 
 
sess.contains user_load? false 
 
22375698 
 
sess.contains user_load? false 
 
sess.contains user_get? true 
 
ghj 
 
sess.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、没有莫名其妙的问题,想起老大对我说的一句公告。 哈哈 ,这就是我中秋节的礼物了 ^^