我有两个定义如下的实体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 集。然后,我将此数据发送到我的 UI,并获取更新的副本,然后我尝试将其保留。用户更新 MasterItem 对象中的字段,但不触及 CriticalItems 集或其中的任何内容 - 它保持未修改。
当我的 save() 方法被调用时,Hibernate 坚持为关键项目集中的每个项目发送 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
(呃)。一旦我解决了这个问题,异常就消失了。