Hibernate вложенные транзакции / сеансы и прокси-ассоциации
Я использую hibernate 4 и spring-aop для обработки транзакций, чтобы всегда была открытая транзакция на стороне сервера.
Я хочу создать вложенную транзакцию, чтобы работать с ней изолированно, но я получаю ошибку: незаконная попытка связать прокси с двумя открытыми сеансами. Смотрите пример ниже:
Объект 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.
1 ответ
Вы должны убедиться, что между двумя сеансами нет общих управляемых объектов Hibernate. т.е. убедитесь, что истинная глубокая копия MusicCollection сделана в методе replicateMusicCollection().
В опубликованном вами коде, если mc.getOwner() представляет управляемый объект Hibernate, который является общим, необходимо убедиться, что он загружается заново во вложенном сеансе.