我遇到一个问题,即实体经理持有一个我认为在同花顺期间没有改变的实体。
我知道以下代码是问题,因为如果我将其注释掉,则实体不会持久存在。在这段代码中,我所做的只是加载实体并调用一些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所做的更改将丢失。
我们目前的理论是,实体经理正在将实体与基础记录进行比较,发现它不同,然后坚持下去。
有人可以解释或确认我们所看到的行为吗?
答案 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。
请检查Teacher
和hashCode()
,查看相关的权利,所有相关实体以及写入数据库的任何其他组件/用户类型。
答案 2 :(得分:1)
如果你的getter正在执行任何逻辑,以便它返回除了hibernate发送给setter之外的其他东西,那么它将被标记为脏。例如,如果你的getter逻辑在hibernate从数据库中给你一个null时返回0,那么它将被标记为脏,因为它看起来好像已经改变了。我不知道有办法告诉hibernate不要将这种变化标记为使实体变脏。