【问题标题】:update() and merge behave differently in case of updating an item in OneToMany collectionupdate() 和 merge 在更新 OneToMany 集合中的项目时表现不同
【发布时间】:2015-09-11 01:24:16
【问题描述】:

我有一个像下面这样的类:

@Entity
@Table(name="work")
public class Work {

    @Id
    @Column(name="id")
    private String id;


    @OneToMany(orphanRemoval=true ,mappedBy="work", cascade=CascadeType.ALL , fetch=FetchType.EAGER)
    private List<PersonRole> personRoleList;
}

由于我是一个网络应用程序,当我更新(来自客户端)personRoleList 项目并调用时:

session.update(work); //`work` is in detached state

它不会更新现有的personRoleList 项目它实际上添加了一个新项目。

其他一些人也有同样的问题。联系人:
using-saveorupdate-in-hibernate-creates-new-records-instead-of-updating-existi
jpa-onetomany-not-deleting-child

我尝试了所有建议的解决方案,但没有一个对我有用。

但是然后我就试过了:

 session.merge(work);  //replacing session.update(work)

按预期工作。!!

这就是我感到困惑的地方。因为对于这种 OneToMany 关系中的行为差异,我找不到任何解释(或者我可能错过了)。我阅读了一些主题以了解update()merge() 之间的区别并阅读了文档。参考:

what-are-the-differences-between-the-different-saving-methods-in-hibernate

differences-among-save-update-saveorupdate-merge-methods-in-session

但仍不清楚造成这种差异的行为模式/逻辑/步骤是什么?

【问题讨论】:

  • 当您使用分离的实体时,您有可能拥有多个实体。现在,当您想要持久化更改时,您需要告诉 hibernate 应该进行哪些更改,因为可能有多个脏版本。因此,您必须使用合并来进行正确的更改。
  • 您是在询问存在这些不同方法的原因,还是询问合并有效而更新无效的原因?
  • 我在问为什么合并有效而更新无效? @泰勒

标签: java hibernate jpa


【解决方案1】:

Merge 尝试将当前瞬态对象与当前由会话管理的持久对象关联起来,方法是将它们“合并”到一个实体中。它的预期用途是当您有一个分离的对象一个附加的对象并希望解决它们。

merge() 中,如果会话中还没有托管实例,Hibernate 将从数据库中读取实体。在您的示例中,这将导致 Hibernate 急切地加载集合(由于 fetch=FetchType.EAGER)。然后,当您的会话结束时,Hibernate 将检查集合中的更改(由于cascade=CascadeType.ALL),并将在数据库中执行适当的更新。

这与update() 场景不同,因为在更新中,Hibernate 总是(默认情况下)假定对象是脏的并安排更新。此更新可能是导致在您的集合中创建新元素的原因 - Hibernate 在发出 UPDATE 之前没有查看数据库以将集合带入会话。

我敢打赌,您可以通过设置获得update() 所需的行为

select-before-update="true"

在您的类映射中或使用lock 方法在进行更改之前将您的对象重新附加到会话。

来自Java Persistence with Hibernate

的第9章

item 对象在传递给之前或之后是否被修改都没有关系 更新()。这里重要的是对 update() 的调用将分离的实例重新附加到新的 Session(和持久性上下文)。休眠 始终将对象视为脏对象并安排 SQL UPDATE,该更新将在刷新期间执行。您可以在图 9.8 中看到相同的工作单元。 您可能会感到惊讶,并且可能希望 Hibernate 可以知道您 修改了分离项的描述(或者 Hibernate 应该知道你做了 不修改任何东西)。但是,新的 Session 及其新的持久性上下文 没有这个信息。分离的对象也不包含您所做的所有修改的内部列表。 需要数据库中的 UDPATE。避免此 UDPATE 语句的一种方法是 使用 select-before-update="true" 配置 Item 的类映射 属性。 Hibernate 然后通过执行一个 SELECT 语句并将对象的当前状态与当前数据进行比较- 基础状态。

【讨论】:

    猜你喜欢
    • 2019-06-13
    • 2012-05-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多