onetomany 集合持有者的版本控制失败

发布于 2024-08-30 19:55:23 字数 818 浏览 6 评论 0原文

给定父实体

@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: 行已被另一事务更新或删除(或未保存值映射不正确):

事实上,hibernate 发出两个 sql 更新:一个更改父属性,另一个更改子属性。您知道一种摆脱父更新更改子的方法吗?更新会导致乐观锁效率低下和误报。请注意,子级和父级都正确地将其状态保存在数据库中。

Hibernate 版本是 3.5.1-Final

given parent entity

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

and child one

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

While updating both parent and child in one transaction, org.hibernate.StaleObjectStateException is thrown: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect):

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. Note, that both child and parent save their state in DB correctly.

Hibernate version is 3.5.1-Final

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

讽刺将军 2024-09-06 19:55:23

(...) 事实上,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());
}

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

(...) Indeed, hibernate issues two sql updates: one changing parent properties and another changing child properties.

If you updated both parent and child in one transaction, isn't this the expected result?

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.

I don't understand the problem and couldn't reproduce it. The following test method (that runs inside a transaction) works for me (and it generates two updates as expected since I modified both the parent and one child).

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

If this is not representative of your situation, please clarify.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文