FrozenSorrow 2008-09-13 17:10
浏览 174
已采纳

hibernate 的缓存使用问题

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

[code="java"]
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();
}

}
[/code]
HibernateSessionFactory 是MyEclipse 生成的

[b]问题补充:[/b]
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 加上
这时候打印的结果是 :
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);

这两个程序(加不加
)都是 session:org.hibernate.impl.SessionImpl()
根据这个打印结果并不能看出什么

所以关键是 这段话
不太清楚 他到底有什么作用 应该不是 一级缓存 二级缓存 或 查询缓存
最后谢谢您的解答 ^^

[b]问题补充:[/b]
多谢gotothework的 回答
你说的这几种策略我也知道
但是关键是加上这段话后
不需要访问数据库 就可以直接出现结果了 (详细描述见上)

而我认为 这个查询结果不是 一级缓存 二级缓存 或 查询缓存 里面的内容
但是如果不是
hibernate 又是如何管理这部分缓存的
抑或还是我的理解有误?
[b]问题补充:[/b]
To gotothework :
在调用sess.close()这个方法以前,一级缓存是一直有效的.所以应该是由一级缓存里调用出来的.
当你查询时,会首先从一级缓存中寻找,如果查找不到,还会从二级缓存中寻找,如果还未找到,就会从数据库中查询.

我明白

你见我第二个问题补充,现在问题是 其他配置(二级缓存 查询缓存 都不配置),仅在Tuser.hbm.xml 加上

打印结果表明: 第二次查询结果 没有访问数据库 就直接返回结果了

[b]问题补充:[/b]
To gotothework :
在您说的这种情况下
hibernate是使用哪种缓存呢? 一级缓存?
但是如果同样的程序
不在 Tuser.hbm.xml 加上
仍是需要先后访问两次数据库的
所以这段 代码作用很诡异
难道加了这段话就保存了一级缓存的数据?

您说的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的。
但是仍未查询数据库就获得结果了
[b]问题补充:[/b]
哈哈 问题搞定 忘了hibernate 是默认启动二级缓存 以及使用 Cache provider: org.hibernate.cache.EhCacheProvider.
我上述的问题现象其实还是使用Hibernate的 二级缓存的

main - Second-level cache: enabled
INFO main - Query cache: disabled
INFO main - Cache provider: org.hibernate.cache.EhCacheProvider
INFO main - Optimize cache for minimal puts: disabled
INFO main - Structured second-level cache entries: disabled

总结:
1、使用二级缓存的话 仅仅必须在 Tuser.hbm.xml 加上
其他设置使用的是Hibernate 里面jar包的默认配置文件
当然如果需要高级应用,那就需要自定义配置文件了
2、对于Hibernate,遇到不明白的问题,建议加上true
并打印debug级别日志
3、Session sess = HibernateSessionFactory.getCurrentSession(); 仍是获得新的session 实例的
同时 一级缓存(Session Cache)是在session.close() 调用后就失效的,跟当前没关系 (不知道理解有没有问题)
4、没有莫名其妙的问题,想起老大对我说的一句公告。 哈哈 ,这就是我中秋节的礼物了 ^^

  • 写回答

4条回答 默认 最新

  • iteye_18036 2008-09-13 20:58
    关注

    刚才是我理解错你的意思了,
    [code="java"]Session sess = HibernateSessionFactory.getCurrentSession();[/code]
    如果你这么去调用,将会把当前线程与Session绑定,而且在线程结束时,Hibernate会自动的关闭这个与线程绑定的Session,不需要你手动关闭.即使你手动的关闭也不会起作用,因为你当前的线程没有结束.所以,当你第二次调用[code="java"]Session sess = HibernateSessionFactory.getCurrentSession();[/code]
    这个方法的时候,其实获得的Session与第一次获得的是同一个,这就是为什么第二次直接返回的结果,而没有去数据库中查询.
    这里你可以试一下openSession(),他是每次都创建一个新的Session实例.

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(3条)

报告相同问题?

悬赏问题

  • ¥30 这是哪个作者做的宝宝起名网站
  • ¥60 版本过低apk如何修改可以兼容新的安卓系统
  • ¥25 由IPR导致的DRIVER_POWER_STATE_FAILURE蓝屏
  • ¥50 有数据,怎么建立模型求影响全要素生产率的因素
  • ¥50 有数据,怎么用matlab求全要素生产率
  • ¥15 TI的insta-spin例程
  • ¥15 完成下列问题完成下列问题
  • ¥15 C#算法问题, 不知道怎么处理这个数据的转换
  • ¥15 YoloV5 第三方库的版本对照问题
  • ¥15 请完成下列相关问题!