防止Hibernate会话刷新/存储无效的脏实体

时间:2022-12-05 08:03:40

I would like to know which approach to take to prevent Hibernate 4.3.4 (with Spring and Hibernate Vaidator) from flushing dirty entities. In my code, i use a manual implementation of Hibernate Validator (a .validate() method within the instance itself), which gets called just before saving an entity. The validate() method returns a list of errors, if any are found, otherwise a Session.update() is called to store the entity, followed by a commit of the transaction.

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

This works, but when the instance itself is manipulated (posted/ request parameters are set in the entity) the entity and corresponding Hibernate session are marked 'dirty' and the entity is stored with the next Session.flush().

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

In my case, i would like to have explicit control over the entities which may be stored and prevent any dirty entity from being stored, how would i achieve this?

在我的情况下,我想明确控制可能存储的实体并防止存储任何脏实体,我将如何实现这一目标?

EDIT:

I know i can manually regulate this by evicting an entity (or clearing and reintroducing an entity via a merge), but this is not my aim. Rather than having to regulate the persistency manually, i would like to have the offset situation that no entity which was not explicitly saved and of which the transaction was not explicitly committed, will not get stored to the database (e.g. via an interceptor?).

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

1 个解决方案

#1


7  

If you modify entities and explicitly want them not to be flushed, you can detach them before modifying. The detached entities will no longer be managed by the persistence context.

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

Hibernate API:

session.evict(myEntity)

JPA:

entityManager.detach(myEntity)

EDIT: In case you want to detach all entities and manage only some of them, you can clear your persistence context first and then merge the entites you do need to be managed:

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

Hibernate API:

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

JPA:

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

EDIT 2 All changes to managed entities are flushed on transaction commit. I am not aware of any feature of JPA or Hibernate that can turn this behavior off. So in addition to detaching some or all entities, you have some other choices, but none is exactly what you are looking for:

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

  • fetching the entities outside a transaction, so they are detached immediately. This seems to come closest to what you want - no hassle with managed changes, only explicit merging would save an entity and you would have to deal less with the persistence API. However you would still need to open a session to merge the entities you do want to be saved with changes.

    获取事务外部的实体,因此它们会立即分离。这似乎最接近你想要的 - 没有管理变更的麻烦,只有显式合并会保存一个实体,你将不得不减少持久性API。但是,您仍然需要打开一个会话来合并您想要保存的实体和更改。

  • mapping query results to DTOs/POJOs (which are always detached) using the NEW operator in your queries. This approach has the advantage of separating the persistence mapping from the application. However introducing a bunch of new classes may not be worth it, and not doing it consistently across the application adds conceptual complexity.

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

  • working inside a transaction, but rolling back instead of committing. You would not be able to save anything, and it is kind of a crude way to prevent changes from being synced with the DB. Unfortunately, you have to either commit or rollback a transaction eventually.

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

  • creating deep copies of the entities to change them. Frankly, this doesn't make much sense to me neither, just adding it for the sake of completeness.

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

EDIT 3 Though not specified by the JPA spec, both Hibernate and Eclipselink allow marking transactions or even result sets from a single query as read-only. This could be useful for you, as

编辑3虽然JPA规范没有规定,但Hibernate和Eclipselink都允许将单个查询中的事务或结果集标记为只读。这对你来说很有用

When a persistent object is read-only, Hibernate does not dirty-check simple properties

当持久对象是只读的时,Hibernate不会检查简单属性

Change flushing gets a bit more complicated when it comes to relationships. Please refer to this documentation for Hibernate or this one for Eclipselink.

在涉及到人际关系时,改变冲洗会变得更加复杂。有关Hibernate的信息,请参阅此文档,或者参考Eclipselink的此文档。

#1


7  

If you modify entities and explicitly want them not to be flushed, you can detach them before modifying. The detached entities will no longer be managed by the persistence context.

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

Hibernate API:

session.evict(myEntity)

JPA:

entityManager.detach(myEntity)

EDIT: In case you want to detach all entities and manage only some of them, you can clear your persistence context first and then merge the entites you do need to be managed:

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

Hibernate API:

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

JPA:

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

EDIT 2 All changes to managed entities are flushed on transaction commit. I am not aware of any feature of JPA or Hibernate that can turn this behavior off. So in addition to detaching some or all entities, you have some other choices, but none is exactly what you are looking for:

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

  • fetching the entities outside a transaction, so they are detached immediately. This seems to come closest to what you want - no hassle with managed changes, only explicit merging would save an entity and you would have to deal less with the persistence API. However you would still need to open a session to merge the entities you do want to be saved with changes.

    获取事务外部的实体,因此它们会立即分离。这似乎最接近你想要的 - 没有管理变更的麻烦,只有显式合并会保存一个实体,你将不得不减少持久性API。但是,您仍然需要打开一个会话来合并您想要保存的实体和更改。

  • mapping query results to DTOs/POJOs (which are always detached) using the NEW operator in your queries. This approach has the advantage of separating the persistence mapping from the application. However introducing a bunch of new classes may not be worth it, and not doing it consistently across the application adds conceptual complexity.

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

  • working inside a transaction, but rolling back instead of committing. You would not be able to save anything, and it is kind of a crude way to prevent changes from being synced with the DB. Unfortunately, you have to either commit or rollback a transaction eventually.

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

  • creating deep copies of the entities to change them. Frankly, this doesn't make much sense to me neither, just adding it for the sake of completeness.

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

EDIT 3 Though not specified by the JPA spec, both Hibernate and Eclipselink allow marking transactions or even result sets from a single query as read-only. This could be useful for you, as

编辑3虽然JPA规范没有规定,但Hibernate和Eclipselink都允许将单个查询中的事务或结果集标记为只读。这对你来说很有用

When a persistent object is read-only, Hibernate does not dirty-check simple properties

当持久对象是只读的时,Hibernate不会检查简单属性

Change flushing gets a bit more complicated when it comes to relationships. Please refer to this documentation for Hibernate or this one for Eclipselink.

在涉及到人际关系时,改变冲洗会变得更加复杂。有关Hibernate的信息,请参阅此文档,或者参考Eclipselink的此文档。