2014-12-03 3 views
0

Я использую hibernate 4 и spring-aop для обработки транзакций, чтобы всегда была открытая транзакция на стороне сервера.Hibernate вложенные транзакции/сеансы и ассоциации прокси

Я хочу создать вложенную транзакцию для работы над ней изолированно, но я получаю сообщение об ошибке: Незаконная попытка связать прокси с двумя открытыми сеансами. См. Пример ниже:

Объект e2 создан с данными из сохраняемого объекта e1 и сохраняется во вложенной транзакции. 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(); 
} 

Maven проект с подробным теста на [https://github.com/cemartins/test-cases].

ответ

0

Вы должны убедиться, что между двумя сеансами нет общих управляемых объектов Hibernate. то есть убедитесь, что в методе replicateMusicCollection() выполняется истинная глубокая копия MusicCollection.

В коде, который вы опубликовали, если mc.getOwner() представляет совместно используемый объект управления Hibernate, вам необходимо убедиться, что он загружен заново во вложенном сеансе.

Смежные вопросы