强制Hibernate查询访问数据库

10

我已经将一个实体加载到我的事务中并更改了该实体的属性。 事务尚未提交。现在我想获取更改属性的原始值。

我尝试使用类似于 select p.property from Person p where p.id = 1 的HQL查询来查询已加载到事务中的实体ID。

我在执行查询之前设置了query.setHint("org.hibernate.cacheMode", CacheMode.IGNORE); ,但没有成功。Hibernate返回设置在当前事务中的值,而不是来自数据库的值。

有什么解决方法吗?


你是否遇到过Hibernate抱怨同一实体在会话中出现两次的问题?听起来你可能需要重新审查实现方式。 - Anthony Bishopric
4个回答

11
我已经将一个实体加载到我的事务中并更改了该实体的属性。该事务尚未提交。现在,我想获取更改后的属性的原始值。
简而言之,你需要自己跟踪旧值。
我曾尝试使用类似于“select p.property from Person p where p.id = 1”的HQL查询,并用事务中加载的实体的ID。Hibernate会为给定的数据库标识符加载唯一版本的实体到会话(第一级缓存)中。这种方法行不通。
我已经在执行查询之前设置了query.setHint("org.hibernate.cacheMode",CacheMode.IGNORE)。此提示用于影响查询缓存(依赖于第二级缓存),这不会影响您当前的“问题”。
有没有什么解决方案?
要么
使用session.refresh()强制重新加载实体(您将失去更改);
像最初提到的那样存储先前的值;
调用执行另一个事务中的查询的服务。

6
无状态会话对我有用。
StatelessSession statelessSession = sessionFactory.openStatelessSession();
try {
    return statelessSession.get(Ticket.class, ticketKey, LockMode.READ)
} finally {
   statelessSession.close()
} 

2
这可能有所帮助:
如果您想强制查询缓存刷新其区域(忽略其中找到的任何缓存结果),则可以使用 org.hibernate.Query.setCacheMode(CacheMode.REFRESH)。与给定查询定义的区域配合使用,Hibernate将有选择地强制刷新存储在该特定区域中的结果。这在底层数据可能已通过其他流程更新并且是比批量驱逐区域的 org.hibernate.SessionFactory.evictQueries() 更有效的替代方法。
(来自http://docs.jboss.org/hibernate/stable/core/reference/en/html/performance.html,第20.4.2节)。
然而,它的使用意图是在其他进程更新数据库时使用,并应谨慎使用。您的情况不同。由于此方法发生在任何事务之外,因此您应确保它不会与您的设计发生冲突。也许您可以重构调用流程以避免这种行为,在缓存进行修改之前从另一个源或修改之前检索该字段...

回顾我的答案,我发现它并没有完全解决您的问题。即使您完全禁用了第二级缓存,实体数据可能仍然从第一级缓存(会话)获取。为此,您应该刷新或清除对象……但是然后您应该在事务提交时重新输入要保存的字段。 - Sebastian

1

唯一的方法是在当前事务之外运行查询。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接