1

指定された親エンティティ

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

と子1

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

1 つのトランザクションで親と子の両方を更新しているときに、org.hibernate.StaleObjectStateException がスローされます: 別のトランザクションによって行が更新または削除されました (または、保存されていない値のマッピングが正しくありませんでした):

実際、hibernate は 2 つの SQL 更新を発行します。1 つは親プロパティを変更し、もう 1 つは子プロパティを変更します。親の更新が子を変更するのを取り除く方法を知っていますか? この更新により、楽観的ロックの非効率性と誤検知が発生します。子と親の両方が状態を DB に正しく保存することに注意してください。

Hibernate のバージョンは 3.5.1-Final です

4

1 に答える 1

0

(...)実際、hibernateは2つのSQL更新を発行します。1つは親プロパティを変更し、もう1つは子プロパティを変更します。

1つのトランザクションで親と子の両方を更新した場合、これは期待される結果ではありませんか?

親の更新を変更する子を取り除く方法を知っていますか?この更新により、非効率と楽観的ロックの誤検知の両方が発生します。

問題がわからず、再現できませんでした。次のテストメソッド(トランザクション内で実行)は私のために機能します(そして、親と1つの子の両方を変更したので、期待どおりに2つの更新が生成されます)。

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

これがあなたの状況を表していない場合は、明確にしてください。

于 2010-04-28T07:04:34.853 に答える