我是 Hibernate 的新手,我知道一级缓存是 session 范围的,二级缓存是跨 session 的,假设我有一个包含字段 Id 和 Name 的实体 Person。
创建 session1 并加载一个人,Id=1,Name="AAA"
创建 session 2,更新此人,
session.saveOrUpdate(person), Id=1, Name="BBB"返回session1并再次更新, session.saveOrUpdate(person), Id=1, Name="AAA"
以下是我对 hibernate 内部功能的猜测:
第 1 步
hibernate搜索session1的1级缓存,什么也没有
hibernate搜索二级缓存,什么也没有
hibernate 搜索数据库
实体存储在level1和level2缓存中
现在 level1 和 level2 缓存都有一个实体,即 id=1 且 name="AAA"的 person
第 2 步
hibernate搜索session2的level1缓存,什么都没有
hibernate搜索二级缓存,获取实体(id=1且name=“AAA”的人)
将此实体存储到session2的一级缓存中
将此实体与 session.saveOrUpdate(person) 的参数进行比较
名称已更改,因此需要更新
session2的level1缓存已更新
二级缓存已更新
数据库已更新
第 3 步
hibernate搜索session1的level1缓存,得到实体(id=1且name=“AAA”的人)
将此实体与 session.saveOrUpdate(person) 的参数进行比较
没有任何改变
所以数据库不会更新?
我会尝试编写一些测试代码,但在此之前,如果有人能指出上面的任何误解,我将不胜感激,这将有助于我更深入地理解 hibernate 缓存。
提前致谢。
最佳答案
除了以下假设之外,您的大多数假设都是正确的:
saveOrUpdate 不用于传播更新更改,而是用于:
- 保留一个临时实体(例如保存)
- 重新附加分离的实体(例如更新)
当您在 session 中加载实体时,它会被加载到一级缓存中,并且您对实体所做的任何更改都将在刷新期间被发现并传播。因此在这种情况下您不必调用 saveOrUpdate。
在步骤 3) 的示例中,Hibernate 不会检测到第一个 session 中的任何更改,因此它无需更新任何内容,即使其他 session 已经更新了实体。
为了防止“丢失更新”,Hibernate 提供了:
- 乐观锁定(@Version)
- 悲观锁定(指示数据库获取锁)
如果您选择乐观锁定,并在步骤 3 中将实体名称更改为“CCC”,您将收到 org.hibernate.StaleObjectStateException(在刷新期间),表明您尝试使用的实体的版本已过时保存。
关于java - Hibernate 一级和二级缓存如何与多个 session 一起工作,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24694379/