【问题标题】:Prevent Hibernate session from flushing/ storing invalid dirty entities防止 Hibernate 会话刷新/存储无效的脏实体
【发布时间】:2014-06-06 12:03:36
【问题描述】:

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

这可行,但是当实例本身被操纵(在实体中设置发布/请求参数)时,实体和相应的 Hibernate 会话被标记为“脏”,并且实体与下一个 Session.flush() 一起存储。

就我而言,我想明确控制可能存储的实体并防止存储任何脏实体,我将如何实现这一点?

编辑:

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

【问题讨论】:

    标签: java hibernate session validation


    【解决方案1】:

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

    休眠 API:

    session.evict(myEntity)

    JPA:

    entityManager.detach(myEntity)

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

    休眠 API:

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

    JPA:

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

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

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

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

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

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

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

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

    当涉及到关系时,更改刷新会变得有点复杂。请参考this documentation for Hibernatethis one for Eclipselink

    【讨论】:

    • 嗨 Kostja,这就是“逆”解决方案,但不是我的目标。我想要的是反之亦然的情况,只有明确保存和提交的实体可以被刷新 - 默认情况下,如果可能的话,不分离它们。
    • 当然,您可以双向修改持久化上下文。请查看编辑。
    • 快到了,但仍然不完全是我想要实现的目标。我真的不想担心脏实体并以您描述的方式调节持久性,而是,例如,通过拦截器,当它们未显式保存且事务未显式提交时,永远不要(自动)刷新这些实体,默认情况下,无需在休眠会话中重新引入它们,也无需在刷新之前驱逐它们。
    • 好吧,AFAIK 你无法配置持久性提供程序以按照你想要的方式运行。但是,还有一些其他选择需要考虑。请查看编辑。
    • 感谢 kostja 的出色反馈,我将研究另一种方法,使用带有 findDirty 和 onDirtyFlush 实现的拦截器,这可能会给我一种摆脱脏提交的方法。但就像您已经表达的那样,这与持久上下文的本质背道而驰。
    猜你喜欢
    • 1970-01-01
    • 2019-03-26
    • 1970-01-01
    • 1970-01-01
    • 2013-10-08
    • 2014-07-08
    • 2016-09-11
    • 1970-01-01
    • 2016-05-06
    相关资源
    最近更新 更多