给定父实体
@Entity
public class Expenditure implements Serializable {
...
@OneToMany(mappedBy = "expenditure", cascade = CascadeType.ALL, orphanRemoval = true)
@OrderBy()
private List<ExpenditurePeriod> periods = new ArrayList<ExpenditurePeriod>();
@Version
private Integer version = 0;
...
}
和 child 一
@Entity
public class ExpenditurePeriod implements Serializable {
...
@ManyToOne
@JoinColumn(name="expenditure_id", nullable = false)
private Expenditure expenditure;
...
}
在一个事务中更新父级和子级时,会抛出 org.hibernate.StaleObjectStateException:行已被另一事务更新或删除(或未保存值映射不正确):
事实上,hibernate 发出两个 sql 更新:一个更改父属性,另一个更改子属性。您知道一种摆脱父更新更改子的方法吗?更新会导致乐观锁效率低下和误报。请注意,子级和父级都正确地将其状态保存在数据库中。
Hibernate 版本为 3.5.1-Final
最佳答案
(...) Indeed, hibernate issues two sql updates: one changing parent properties and another changing child properties.
如果您在一个事务中更新了父级和子级,这不是预期的结果吗?
Do you know a way to get rid of parent update changing child? The update results both in inefficiency and false positive for optimistic lock.
我不明白这个问题,也无法重现它。以下测试方法(在事务内运行)适合我(由于我修改了父项和一个子项,它按预期生成了两个更新)。
@Test
public void testUpdate() {
Expenditure expenditure = new Expenditure();
ExpenditurePeriod expenditurePeriod1 = new ExpenditurePeriod();
ExpenditurePeriod expenditurePeriod2 = new ExpenditurePeriod();
expenditure.getPeriods().add(expenditurePeriod1);
expenditure.getPeriods().add(expenditurePeriod2);
expenditurePeriod1.setExpenditure(expenditure);
expenditurePeriod2.setExpenditure(expenditure);
em.persist(expenditure);
em.flush();
assertNotNull(expenditure.getId());
assertNotNull(expenditurePeriod1.getId());
assertNotNull(expenditurePeriod2.getId());
assertEquals(Integer.valueOf(0), expenditure.getVersion());
assertEquals(Integer.valueOf(0), expenditurePeriod1.getVersion());
assertEquals(Integer.valueOf(0), expenditurePeriod2.getVersion());
expenditure.setProperty("a");
expenditurePeriod1.setProperty("b");
em.merge(expenditure);
em.flush();
assertEquals(Integer.valueOf(1), expenditure.getVersion());
assertEquals(Integer.valueOf(1), expenditurePeriod1.getVersion());
assertEquals(Integer.valueOf(0), expenditurePeriod2.getVersion());
}
如果这不能代表您的情况,请澄清。
关于java - onetomany 集合持有者的版本控制失败,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2721621/