Hibernate 缓存问题+自动Update问题。求高手求大神。

jiakai0419 2011-12-09 06:11:00
最近初学Hibernate有一问题不是很明白。

缓存,一般就是内存中(或者是本地磁盘) 开辟一块区域。
暂存一些东西,下次如果再想取某个东西的时候,先看看缓存中有没有,有的话直接拿缓存中的就可以了,就不用去数据库中取了。

那Hibernate的一级缓存中(也就是那块内存区域)
是备份了JVM内存中persistant状态的对象的引用呢,
还是备份JVM内存中persistant状态的对象呢?


如果备份的是引用的话就不涉及到 内存中对象与缓存中对象同步(保持一样)的问题了。

如果备份的是对象的话那么就涉及到了 内存中对象如何与缓存中对象的同步问题了。


我个人感觉应该是备份了对象而非引用


还有一个问题,就是关于persistant状态对象自动Update 具体是怎么实现的?


Hibernate 的一级缓存应该是靠Session来管理的吧(具体点说,应该是Session中的一个Map吧)?


求高手,求大神。




...全文
309 12 打赏 收藏 转发到动态 举报
写回复
用AI写文章
12 条回复
切换为时间正序
请发表友善的回复…
发表回复
magong 2011-12-11
  • 打赏
  • 举报
回复
[Quote=引用 9 楼 jiakai0419 的回复:]

能给我你QQ吗?

有问题可以请教一下你。
[/Quote]
QQ不用。欢迎站内私信。
magong 2011-12-10
  • 打赏
  • 举报
回复
[Quote=引用楼主 jiakai0419 的回复:]
我个人感觉应该是备份了对象而非引用
[/Quote]
其实你说的“备份”动作确实是存在的。
session中确实会持有对象的原始快照,快照来源于最近的一次select,反映数据库中的“最新”数据状态。
但这个快照不会让用户触及。
flush时如果快照不存在,会当场补做一个select。

使用延迟加载的时候,我们拿到的对象(也就是session中持有的对象)是一个代理对象,可以方便我们快速判断属性是否脏的,但并不是任何情况下总是能拿到代理对象。所以逐属性比较值是否更新过 这个过程是不可少的。
参照
http://stackoverflow.com/questions/82429/when-hibernate-flushes-a-session-how-does-it-decide-which-objects-in-the-sessio
magong 2011-12-10
  • 打赏
  • 举报
回复
[Quote=引用楼主 jiakai0419 的回复:]
还有一个问题,就是关于persistant状态对象自动Update 具体是怎么实现的?
Hibernate 的一级缓存应该是靠Session来管理的吧(具体点说,应该是Session中的一个Map吧)?
[/Quote]
update的问题,有三个方面。
①确实如你所说,session对象管理一级缓存。
②update(也就是flush)的时机的问题。一般在 手动flush、事务commit、session close等几个时机触发update动作
③如何决定脏数据的逻辑。这个2楼说的是对的,Hibernate默认是采用“select/比较每个属性是否更新过/全字段update”这种逻辑的。不过可以配置改变这里的策略。
magong 2011-12-10
  • 打赏
  • 举报
回复
[Quote=引用楼主 jiakai0419 的回复:]
那Hibernate的一级缓存中(也就是那块内存区域)
是备份了JVM内存中persistant状态的对象的引用呢,
还是备份JVM内存中persistant状态的对象呢?


如果备份的是引用的话就不涉及到 内存中对象与缓存中对象同步(保持一样)的问题了。

如果备份的是对象的话那么就涉及到了 内存中对象如何与缓存中对象的同步问题了。

我个人感觉应该是备份了对象而非引用
[/Quote]
缓存中的对象和你才session.get/load/merge得到的对象是同一个对象,缓存和你的变量同时引用它。(或者用你的话,“备份”引用)
游一游走一走 2011-12-10
  • 打赏
  • 举报
回复
说下个人的理解:
第一点,我觉得楼主所说的一级缓存对象与JVM内存中persistant状态的对象这两个应该是引用关系,比如通过ID加载时,首先通过ID去查询缓存,找到就直接返回缓存对象了,之后对于persistant状态对象的修改直接会反映到缓存对象的修改,此时不需要和数据库交互.......当flush时,hibernate会自动的发现脏数据并同步到数据库
第二点,你可以查阅下hibernate的脏数据处理机制的相关文档,我记得有两种处理方法a).使用代理的方法,对于类似set的有改变实体类容的方法进行拦截,有调用过的标记为脏数据b).缓存保留hibernate加载时的原始镜像,flush时将对象和原始镜像比较,不同则定义为脏数据并同步到数据库.....hibernate使用的应该是第二种
jiakai0419 2011-12-10
  • 打赏
  • 举报
回复
没人回?

求大牛。
jiakai0419 2011-12-10
  • 打赏
  • 举报
回复
[Quote=引用 8 楼 magong 的回复:]

引用 6 楼 jiakai0419 的回复:

我感觉,应该是理解的差不多了。

差不多了。呵呵。
[/Quote]

哥们。你回答我好多问题了。

能给我你QQ吗?

有问题可以请教一下你。
magong 2011-12-10
  • 打赏
  • 举报
回复
[Quote=引用 6 楼 jiakai0419 的回复:]

我感觉,应该是理解的差不多了。
[/Quote]
差不多了。呵呵。
jiakai0419 2011-12-10
  • 打赏
  • 举报
回复
通过楼上二位的讲解。

我可以这么理解吗?

当我们从数据库中取出一个对象的时候,这个对象被加载到JVM内存中。

然后我程序的引用这个对象,缓存同时引用这个对象。

也就是说,缓存中没有new 一个跟这个对象一样的对象,而是保存了一个这个对象的引用。

而且,我通过程序验证,确实是保存的引用。


@Test
public void testGet() {
Session s = sf.getCurrentSession();
s.beginTransaction();
Category jvmC = (Category)s.get(Category.class,1);
Category cacheC = (Category)s.get(Category.class,1);

System.out.println(jvmC == cacheC);
s.getTransaction().commit();
}



flush那个问题。我也理解了。

就是之前有一个快照,然后看看缓存中的引用的对象,跟这个快照一不一样。

如果一样,就更新。


我感觉,应该是理解的差不多了。

62,614

社区成员

发帖
与我相关
我的任务
社区描述
Java 2 Standard Edition
社区管理员
  • Java SE
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧