2012-06-12 3 views
13

Я использую EclipseLink 2.3.0. У меня есть метод, который я звоню из модульного теста (т.е. вне контейнера, не JTA), который выглядит следующим образом:JPA/EclipseLink: EntityManager.getTransaction() создает новую транзакцию или возвращает активную?

EntityManager em = /* get an entity manager */; 
em.getTransaction().begin(); 
// make some changes 
em.getTransaction().commit(); 

Изменения были не будучи сохранялись в базу данных, и смотрели на это для долгое время и, наконец, понял, что EntityManager.getTransaction() фактически возвращает NEW EntityTransaction, а не тот же самый в обоих вызовах. Эффект заключается в том, что первый вызов создает новую транзакцию и начинает ее, а второй вызов создает ДРУГОЕ транзакцию и фиксирует ее. Поскольку первая транзакция никогда не выполнялась, изменения не сохраняются. Мы проверили это так:

log.info(em.getTransaction().toString()); 
log.info(em.getTransaction().toString()); 

Что в результате этих логов:

INFO: org.ecl[email protected]1e34f445 
INFO: org.ecl[email protected]706a4d1a 

Два проверочных, что существует два разных экземпляр другого объекта идентификаторов. Изменение кода на это:

EntityManager em = /* get an entity manager */; 
EntityTransaction tx = em.getTransaction(); 
tx.begin(); 
// make some changes 
tx.commit(); 

... устранить проблему. Теперь, когда я запускаю код, я вижу инструкции SQL, созданные для работы с базой данных, и просматривая в базе данных данные были изменены.

Я был немного удивлен этим результатом, так как я видел многочисленные примеры кода онлайн (для JPA вообще и для EclipseLink специально), которые рекомендуют код, который мы использовали для управления транзакциями. Я искал по всему миру информацию об этом, но ничего не нашел. Так, что происходит?

Я просмотрел спецификацию JPA для чего-то, что точно определяет, что делает getTransaction(), и это было неточно, если транзакция является новой или той же. Есть ли параметр в persistence.xml, который контролирует это? Является ли поведение специфичным для каждой реализации спецификации JPA?

Большое спасибо за любую информацию или руководство.

ответ

1

Спецификация JPA (см. Пункт 7.5.4) содержит явные примеры, показывающие использование getTransaction() для начала и фиксации транзакции. Поэтому ваш код должен быть в порядке.

Ваш тест показывает, что вы получаете два разных объекта, но это не означает, что одна и та же транзакция не используется. Возможно, возвращаемый объект - это просто некоторый прокси-сервер для одного, реального объекта транзакции.

Возможно, сделка совершена или отклонена внутри кода, скрытого под // make some changes.

+1

Возможно, я должен был быть более понятным - код, который я разместил, НЕ работает. Я внес изменения в вопрос, чтобы уточнить. –

+0

Я понимаю это. Я хочу сказать, что он * должен * работать, поскольку спецификация JPA содержит примеры кода whet 'em.getTransaction()' используется для начала и фиксации транзакции. Таким образом, это должно быть ошибкой в ​​EclipseLink, если, как я уже сказал, код между началом и коммитом уже совершает или откатывает транзакцию. Мой ответ не является решением вашей проблемы, а является подтверждением того, что код должен работать. Я предлагаю подавать ошибку EclipseLink. –

5

Использование getTransaction() работает в JPA и EclipseLink (так работают наши собственные тесты).

Я думаю, вы делаете что-то еще очень странное.

Вы используете Spring или другой слой? Пожалуйста, укажите весь код и persistence.xml для вашего теста. Убедитесь, что вы не используете JTA в вашем файле persistence.xml.

+0

getTransaction() должен вызывать исключение IllegalStateException, если он вызван в менеджере сущностей JTA. –

+0

Нет весны, нет JTA, это вызывается из теста JUnit за пределами контейнера. Код в «внести некоторые изменения» - это 4 строки, создавая новый объект, устанавливая для него целочисленное значение, слияние и флеш. Когда я получу минуту, я создам дистиллированный пример. Возможно, это ошибка EclipseLink. –

0

У вас пытался использовать persist before commit:?

Employee employee = new Employee("Samuel", "Joseph", "Wurzelbacher"); 
    em.getTransaction().begin(); 
    em.persist(employee); 
    em.getTransaction().commit(); 
Смежные вопросы