当前位置: 首页 > 面试题库 >

当收藏未更改时,停止Hibernate更新收藏

齐阎宝
2023-03-14
问题内容

我有两个定义如下的实体bean(删除了无关的东西):

@Entity
@Table(...)
public class MasterItem implements java.io.Serializable {

  private Set<CriticalItems> criticalItemses = new HashSet<CriticalItems>(0);

  @OneToMany(fetch = FetchType.EAGER, mappedBy = "masterItem", orphanRemoval = true,
            cascade = {javax.persistence.CascadeType.DETACH})
    @Cascade({CascadeType.SAVE_UPDATE, CascadeType.DELETE})
    public Set<CriticalItems> getCriticalItemses() {
        return this.criticalItemses;
    }
}

CriticalItems定义如下:

@Entity
@Table(...)
public class CriticalItems implements java.io.Serializable {

    private MasterItem masterItem;

    @ManyToOne(fetch = FetchType.LAZY, optional = false,
            cascade = {javax.persistence.CascadeType.DETACH})
    @Cascade({CascadeType.SAVE_UPDATE})
    @JoinColumn(name = "mi_item_id", nullable = false)
    public MasterItem getMasterItem() {
        return this.masterItem;
    }
}

在我的DAO代码中-我有以下方法:

public MasterItem load(int id) {
    MasterItem results = (MasterItem) getSessionFactory().getCurrentSession()
        .get("com.xxx.MasterItem", id);

}

public void save(MasterItem master) {
    // master has been changed by the UI since it
    getSessionFactory().getCurrentSession().saveOrUpdate(master);
}

当我加载MasterItem时,它会正确加载,并且还会按照指示加载CriticalItems
Set中的数据。然后,我将此数据发送到我的UI,并获得更新的副本,然后尝试将其保留。用户更新MasterItem对象中的字段,但不触摸CriticalItems
Set或其中的任何内容-它保持不变。

调用我的save()方法时,Hibernate坚持要为Set of CriticalItems中的每个项目发送SQL更新,即使这些更新都没有任何改变。

经过一番挖掘,这就是我想发生的事情。当我执行saveOrUpdate()时,Hibernate看到我的MasterItem对象处于分离状态,因此它尝试从磁盘重新加载它。但是,这样做时,它似乎正在使用准备好的语句(该语句在启动时由Hibernate自动创建),并且该准备好的语句不会尝试加入CriticalItems数据。

因此,Hibernate拥有一个更新的MasterItem对象,该对象具有完整的CriticalItems集,但使用不带集合的MasterItem作为其“
previousState”对象。因此,所有CriticalItems都通过SQL(未插入,这本身很有趣)进行更新。

我在注释中做了一些导致这种现象的事情吗?我知道我可以使用拦截器从项目中发现确实发生了更改,或者更改了脏标志以覆盖Hibernate的默认算法-
但这似乎是Hibernate应该在没有我干预的情况下自行处理的事情。

任何见识将不胜感激。

更新: 基于评论,我想我了解saveOrUpdate()和merge()之间的区别。我意识到saveOrUpdate()在所有情况下都会导致SQL
INSERT或SQL UPDATE,并且从理论上讲,这种合并只会在对象从其持久状态更改后才发出更新,但是为了确定,Hibernate必须先通过SQL
SELECT重新加载对象。

因此,我以为我可以回到我的代码中,将saveOrUpdate()更改为merge(),这样就可以了,但事实并非如此。

当我使用merge()时,

org.springframework.orm.hibernate3.HibernateSystemException: could not initialize proxy - no Session; nested exception is org.hibernate.LazyInitializationException: could not initialize proxy - no Session

但是如果我改回saveOrUpdate(),它就可以正常工作。

我终于找到了原因-我没有CascadeType.MERGE@Cascade注释中添加(ugh)。一旦我解决了,异常就消失了。


问题答案:

这是update()和之间的语义差异merge()

摘自Christian Bauer和Gavin King的《
Hibernate的Java持久性》
(我在Hibernate文档中找不到对此行为的清晰解释):

update()方法强制更新到数据库中对象的持久状态,始终调度SQL UPDATE。

在将项目对象传递给update()之前或之后进行修改都没有关系。

Hibernate始终将对象视为脏对象,并计划将在刷新期间执行的SQL UPDATE.。

另一方面,merge()首先查询数据库,如果状态未更改,则不执行更新。

因此,如果要让Hibernate首先查询数据库,则需要使用merge()(尽管update()可以通过@org.hibernate.annotations.Entity(selectBeforeUpdate = true)在实体上指定来替代的默认行为)。



 类似资料:
  • 我是新来的反应。我被困在这件事上,真的很感激你的帮助! 父组件将把一个数组传递到这个子组件中。当我console.log(this.props.repairs)时,它显示了一个4的数组。每当传入修复数组时,我都试图更新this.state.SortedDataList。console.log(this.state)仍然将sortedDataList显示为空数组。 我做错了什么?非常感谢,谢谢你的帮

  • 1.我应该如何将swagger请求传递给Postman,并在获取请求时设置参数,以及在POST/PUT请求时使用它们? 2.每当Swagger上的请求参数发生更改时,我如何更新这些请求?

  • 所以我的应用程序有一个主窗口显示食谱列表,第二个窗口(从主窗口打开)添加新的食谱到列表(有信息)。两个窗口具有相同的视图模型。经过测试,新的制作方法被成功添加到列表中,但是UI没有更新新的制作方法。我也有一个删除按钮在主窗口为每个食谱和它的工作正常。删除的制作方法将在视图模型和UI中删除。我的代码相当长。我希望它是可读的。下面是我的代码(还有很多其他的UI,所以我只显示相关的代码): 主窗口视图

  • 我正在使用Angular的和,如下所示: 我的问题是,当我点击链接时,页面会向下滚动,但在50%的情况下,页面会重新加载,因为URL中的哈希值会发生变化。 如何防止Angular重新加载页面? 更新:我在这里找到了 https://groups.google.com/forum/?fromgroups=#!msg/angular/BY2ekZLbnIM/MORF-z2vHnIJ 那个啊

  • 我尝试创建一个自定义的时间流逝时间,一旦我按住音量键,它就会启动计时器,并假设时间必须在我松开键后停止,但我松开键时遇到问题,计时器仍在移动。请告诉我我错过了什么谢谢 公共布尔onKeyDown(int-keyCode,KeyEvent-event){if((keyCode==KeyEvent.keyCode_-VOLUME_-DOWN

  • 我在字符串数组的流处理中看到了一个有趣的行为。 我在做这样的事 预期结果应该是一组[1,2],但实际结果是[2,1]。toSet()创建一个HashSet而不是SortedSet,所以它不应该扰乱数据的顺序。不知道为什么!!