JPA合并与持久性

时间:2011-12-12 04:17:37

标签: java jpa merge entitymanager persist

到目前为止,我的偏好是始终使用EntityManager的merge()来处理插入和更新。但我也注意到merge在update / insert之前执行了额外的select查询,以确保数据库中不存在记录。

现在我正在开发一个需要对数据库进行大量(批量)插入的项目。从性能的角度来看,在我绝对知道我总是创建一个要保留的对象的新实例的场景中使用persist而不是merge是有意义的吗?

3 个答案:

答案 0 :(得分:69)

merge足够 - persist完成更多工作时,使用merge并不是一个好主意。该主题之前已经discussed on StackOverflow,并且this article详细解释了这些差异,并提供了一些很好的流程图以使事情变得清晰。

答案 1 :(得分:9)

如果像你说的那样,我肯定会坚持persist()

  

(...)我完全知道我总是创建一个新的对象实例来保持(...)

这就是这个方法的全部意义 - 它将在实体已经存在的情况下保护您(并将回滚您的交易)。

答案 2 :(得分:2)

如果您使用的是指定的生成器using merge instead of persist can cause a redundant SQL statement,则会影响性能。

此外,calling merge for managed entities也是一个错误,因为管理实体由Hibernate自动管理,并且dirty checking mechanismflushing the Persistence Context上状态与数据库记录同步。

要了解所有这些是如何工作的,首先应该知道Hibernate将开发人员的思维方式从SQL语句转移到entity state transitions

一旦Hibernate主动管理实体,所有更改都将自动传播到数据库。

Hibernate监视当前附加的实体。但是对于要管理的实体,它必须处于正确的实体状态。

首先,我们必须定义所有实体状态:

  • 新(瞬态)

    新创建的对象尚未与Hibernate Session(又名Persistence Context)关联且未映射到任何数据库表行被视为处于新(暂停)状态。

    要成为持久化,我们需要显式调用EntityManager#persist方法或使用传递持久性机制。

  • 持久(管理)

    持久性实体已与数据库表行关联,并且由当前运行的持久性上下文管理。对此类实体所做的任何更改都将被检测并传播到数据库(在会话刷新时间内)。 使用Hibernate,我们不再需要执行INSERT / UPDATE / DELETE语句。 Hibernate使用transactional write-behind工作方式,并且在当前Session刷新时间的最后一个负责时刻同步更改。

  • 独立式

    当前运行的持久性上下文关闭后,所有先前管理的实体都将分离。将不再跟踪连续更改,也不会发生自动数据库同步。

    要将分离的实体与活动的Hibernate会话相关联,您可以选择以下选项之一:

    • 再附

      Hibernate(但不是JPA 2.1)支持通过Session#update方法重新连接。 Hibernate会话只能为给定的数据库行关联一个Entity对象。这是因为持久性上下文充当内存缓存(第一级缓存),并且只有一个值(实体)与给定密钥(实体类型和数据库标识符)相关联。 只有在没有与当前Hibernate会话关联的其他JVM对象(匹配相同的数据库行)时,才能重新附加实体。

    • 合并

    合并将将分离的实体状态(源)复制到托管实体实例(目标)。如果合并实体在当前会话中没有等效项,则将从数据库中获取一个。 即使在合并操作之后,分离的对象实例仍将继续保持分离状态。

  • 删除

    虽然JPA要求仅允许删除托管实体,但Hibernate还可以删除分离的实体(但只能通过Session#delete方法调用)。 删除的实体仅计划删除,实际的数据库DELETE语句将在会话刷新时执行。

为了更好地理解JPA状态转换,您可以可视化下图:

enter image description here

或者如果您使用Hibernate特定的API:

enter image description here