当实体没有改变时,Hibernate在刷新期间持久化实体

时间:2010-05-18 23:06:22

标签: hibernate jdbc entity

我遇到一个问题,即实体经理持有一个我认为在同花顺期间没有改变的实体。

我知道以下代码是问题,因为如果我将其注释掉,则实体不会持久存在。在这段代码中,我所做的只是加载实体并调用一些getter。

Query qry = em.createNamedQuery("Clients.findByClientID");
qry.setParameter("clientID", clientID);

Clients client = (Clients) qry.getSingleResult();

results.setFname(client.getFirstName());
results.setLname(client.getLastName());
...
return results;

稍后在另一个方法中,我执行另一个命名查询,它导致实体管理器刷新。出于某种原因,上面加载的客户端是持久的。

这是一个问题的原因是因为在所有这些中间,有一些旧代码正在对客户端进行一些直接的JDBC更改。当实体管理器持续存在时,直接JDBC所做的更改将丢失。

我们目前的理论是,实体经理正在将实体与基础记录进行比较,发现它不同,然后坚持下去。

有人可以解释或确认我们所看到的行为吗?

3 个答案:

答案 0 :(得分:2)

我不知道冬眠的内脏,但我的猜测是你是对的。但我不认为hibernate会与db进行比较,而是与本地会话缓存进行比较。

您可以通过将对象设置为readOnly来避免此问题 - 休眠然后不检查更改,例如。

   session.setReadOnly(client, true);

或者,您也可以使用Session.evict()逐出该对象。下次需要该对象时,将从db读入该对象,包括使用自定义JDBC进行的任何更改。

答案 1 :(得分:1)

你是对的,实体经理比较对象(只要它们在会话中不是只读的,被驱逐的,已经调用了session.clear()等),如果它们不匹配那么它会冲出它们。

这个特定的问题之前已经咬过我们,并且导致完全相同的不必要的冲洗问题 - 我们也是一个性能问题,在我们需要flush()会话的紧密循环中,每次我们做了数百个未更改的对象被转储回DB。

在我们的例子中,有问题的实体是正确实现equals()hashCode() - Hibernate显然依赖于那些来检查对象的更改,以及如果它们在某种程度上不正确,那么它别无选择,只能将它们冲洗回来。

从内存(不久前)它实际上是一个没有正确实现hashCode()的附属实体 - 想象一个Student - Teacher关系,其中{{1没有正确实现这些方法。当检查Teacher时,Hibernate在其实体缓存中检查Student,认为它不存在(由于不正确的实现),因此认为Teacher已经改变,将其重新刷回写出新的Student ID。

请检查TeacherhashCode(),查看相关的权利,所有相关实体以及写入数据库的任何其他组件/用户类型。

答案 2 :(得分:1)

如果你的getter正在执行任何逻辑,以便它返回除了hibernate发送给setter之外的其他东西,那么它将被标记为脏。例如,如果你的getter逻辑在hibernate从数据库中给你一个null时返回0,那么它将被标记为脏,因为它看起来好像已经改变了。我不知道有办法告诉hibernate不要将这种变化标记为使实体变脏。