Java 防止休眠会话刷新/存储无效的脏实体

Java 防止休眠会话刷新/存储无效的脏实体,java,hibernate,session,validation,Java,Hibernate,Session,Validation,我想知道采取哪种方法来防止Hibernate 4.3.4(使用Spring和Hibernate Vaidator)刷新脏实体。 在我的代码中,我使用了Hibernate Validator(实例本身中的一个.validate()方法)的手动实现,它在保存实体之前被调用。validate()方法返回错误列表(如果发现),否则调用Session.update()存储实体,然后提交事务 这是可行的,但是当实例本身被操作(在实体中设置了POST/request参数)时,实体和相应的Hibernate会话

我想知道采取哪种方法来防止Hibernate 4.3.4(使用Spring和Hibernate Vaidator)刷新脏实体。 在我的代码中,我使用了Hibernate Validator(实例本身中的一个.validate()方法)的手动实现,它在保存实体之前被调用。validate()方法返回错误列表(如果发现),否则调用Session.update()存储实体,然后提交事务

这是可行的,但是当实例本身被操作(在实体中设置了POST/request参数)时,实体和相应的Hibernate会话被标记为“dirty”,实体与下一个会话一起存储。flush()

在我的情况下,我希望对可能存储的实体有明确的控制,并防止任何脏实体被存储,我将如何实现这一点

编辑:


我知道我可以通过逐出一个实体(或者通过合并清除并重新引入一个实体)来手动调节这一点,但这不是我的目标。与其手动调节持久性,我希望有一种补偿情况,即没有明确保存且事务没有明确提交的实体不会存储到数据库中(例如,通过拦截器?)。

如果修改实体并明确希望它们不被刷新,可以在修改之前拆离它们。分离的实体将不再由持久性上下文管理

Hibernate API:

session.clear();
managedEntity = session.merge(detachedEntity);

JPA:

编辑:如果要分离所有实体并仅管理其中的一部分,可以先清除持久性上下文,然后合并需要管理的实体:

Hibernate API:

session.clear();
managedEntity = session.merge(detachedEntity);
JPA:

编辑2事务提交时刷新对托管实体的所有更改。我不知道JPA或Hibernate的任何功能可以关闭这种行为。因此,除了分离部分或所有实体外,您还有一些其他选择,但没有一个是您想要的:

  • 获取事务外部的实体,以便立即分离它们。这似乎与您想要的最接近——管理的更改没有任何麻烦,只有显式合并才能保存实体,并且您需要更少地处理持久性API。但是,您仍然需要打开一个会话来合并您确实希望保存更改的实体

  • 在查询中使用
    NEW
    操作符将查询结果映射到DTO/POJO(始终分离)。这种方法的优点是将持久性映射与应用程序分离。然而,引入一堆新类可能不值得,并且在整个应用程序中不一致地这样做会增加概念上的复杂性

  • 在事务内部工作,但回滚而不是提交。您将无法保存任何内容,这是一种防止更改与数据库同步的粗糙方法。不幸的是,您最终必须提交或回滚事务

  • 创建实体的深度副本以对其进行更改。坦白地说,这对我来说也没有多大意义,只是为了完整性而添加它

edit3尽管JPA规范没有指定,但Hibernate和Eclipselink都允许将单个查询中的事务甚至结果集标记为只读。这可能对你有用,因为

当持久对象为只读时,Hibernate不会对简单属性进行脏检


当涉及到人际关系时,变化会变得更加复杂。请参考或。

嗨,Kostja,这是“反向”解决方案,但不是我的目标。我希望情况是相反的,只有显式保存和提交的实体可以被刷新-默认情况下,如果可能,不分离它们。当然,您可以通过两种方式修改持久性上下文。请看编辑。差不多了,但仍然不完全是我想要达到的。我真的不想担心脏实体,并按照您描述的方式调节持久性,但是,例如,通过拦截器,当这些实体未显式保存且默认情况下事务未显式提交时,如果不在hibernate会话中重新引入它们,则决不(自动)刷新这些实体,也不必在刷新之前逐出它们。好吧,恐怕您无法配置持久性提供程序以您希望的方式运行。然而,还有一些其他的选择要考虑。请看编辑。感谢kostja的出色反馈,我将研究另一种方法,使用带有findDirty和onDirtyFlush实现的拦截器,这可能会给我一种摆脱脏提交的方法。但正如你已经表达的,这违背了持久性上下文的本质。