版本控制因onetomany收藏持有人而失败

时间:2010-04-27 13:34:06

标签: java hibernate orm versioning optimistic-concurrency

给定父实体

@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;
...
}

和孩子一个

@Entity
public class ExpenditurePeriod implements Serializable {
...
    @ManyToOne
    @JoinColumn(name="expenditure_id", nullable = false)
    private Expenditure expenditure;
...
}

在一个事务中更新父级和子级时,抛出org.hibernate.StaleObjectStateException:Row被另一个事务更新或删除(或者unsaved-value映射不正确):

实际上,hibernate会发出两个sql更新:一个更改父属性,另一个更改子属性。你知道一种摆脱父母更新改变孩子的方法吗?更新导致乐观锁定效率低下和误报。请注意,child和parent都正确地将其状态保存在DB中。

Hibernate版本是3.5.1-Final

1 个答案:

答案 0 :(得分:0)

  

(...)的确,hibernate会发出两个sql更新:一个更改父属性,另一个更改子属性。

如果在一次交易中同时更新了父母和子女,这不是预期的结果吗?

  

你知道一种摆脱父母更新改变孩子的方法吗?更新导致乐观锁定效率低下和误报。

我不明白这个问题,无法重现。以下测试方法(在事务中运行)适用于我(并且它会根据预期生成两个更新,因为我修改了父项和一个子项)。

@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());
}

如果这不能代表您的情况,请澄清。