0

サーバー側で常に開いているトランザクションが存在するように、トランザクションを処理するために hibernate 4 と spring-aop を使用しています。

ネストされたトランザクションを作成して分離して動作させたいのですが、次のエラーが表示されます: プロキシを 2 つの開いているセッションに関連付ける試みが不正です。以下の例を参照してください。

永続化されたエンティティ e1 からのデータで作成され、ネストされたトランザクションに保存されたエンティティ e2。E1 には、完全に初期化されていないディープ グラフがあります。

例外をスローせずに e2 を作成する正しい方法は何でしょうか?

スキームの例:

---
  |
  V
  begin transaction 1
     |
     ---> Read persisted entity e1
                    |
                    |
                    V 

                     begin transaction 2

                     create new transient entity e2
                     copy properties from e1 to e2
                     save e2

                  -- THROWS Illegal attempt to associate a proxy with two open sessions --

                     commit transaction 2

                    |
                    |
     ---------------
     |
     V
  commit transaction 1

コード例:

@Test
public void testSaveInNestedSession() {

    // open first session
    Session session1 = sessionFactory.openSession();
    Transaction transaction1 = session1.beginTransaction();

    // get the existing music collection
    MusicCollection mc = DbUtil.getMusicCollection(session1, "X Collection");

    // create and save a copy of this collection in a nested transaction (will break)
    replicateMusicCollection(mc);

    transaction1.commit();
    session1.close();
}

/**
 * Save a copy of the MusicCollection in a new transaction
 * for isolation purposes
 * @param mc
 */
private void replicateMusicCollection(MusicCollection mc) {

    // open nested session
    Session session2 = sessionFactory.openSession();
    Transaction transaction2 = session2.beginTransaction();

    // create a new transient Music Collection
    MusicCollection newMusic = new MusicCollection();
    newMusic.setName("Collection Y");
    newMusic.setOwner(mc.getOwner());

    for(AudioCd cd : mc.getCdSet()) {
        AudioCd newCd = new AudioCd();
        newCd.setAlbumName(cd.getAlbumName());
        newCd.setAuthor(cd.getAuthor());

        newMusic.addAudioCd(newCd);
    }

    try {
        session2.save(newMusic);
        transaction2.commit();
    }
    catch(HibernateException e) {

        e.printStackTrace();
        transaction2.rollback();

        throw e;
    }

    session2.close();
}

[https://github.com/cemartins/test-cases]で詳細なテスト ケースを含む Maven プロジェクト。

4

1 に答える 1

0

2 つのセッション間で Hibernate 管理オブジェクトが共有されないようにする必要があります。つまり、MusicCollection の完全なディープ コピーが、replicateMusicCollection() メソッドで実行されていることを確認してください。

投稿したコードで、mc.getOwner() が共有されている Hibernate 管理対象オブジェクトを表している場合、ネストされたセッションで新たにロードされるようにする必要があります。

于 2015-06-10T22:12:57.870 に答える