2010-11-19 3 views
3

У меня есть интеграционный тест DAO, в котором я использую общий EntityManager (через Spring, используя SharedEntityManagerCreator). Класс тестирования помечен как @Transactional, как и тестируемый метод DAO.JPA: Всегда ли EntityManager.find() возвращает ту же ссылку на объект для одного и того же ключа?

В обоих тестовом классе и DAO Я retreiving на объект пользователя следующим образом:

User user = em.find(User.class, "test"); 

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

System.out.println("User objects equal = " + (user == dao.getUser())); 

Это напечатано неверно. Я бы ожидал, что каждый вызов EntityManager с использованием того же ключа вернет ту же ссылку на объект и был удивлен (и немного встревожен!), Чтобы узнать, что это не так. Может ли кто-нибудь пролить свет на это? Я переработал свой код, поэтому на самом деле это не проблема (у DAO не должно было быть объекта User в любом случае), но я все равно хотел бы это понять лучше.

Спасибо!

Java 1.6u22, TOPLINK Основы 2.0.1, 2.5.6 Spring

ответ

5

find() возвращает тот же экземпляр внутри области контекста постоянства.

В случае совместного EntityManager (транзакция-области действия контекста персистентности управляемого контейнера, в терминах JPA Spec) Жизненный цикл контекста персистентности привязан к транзакции, поэтому find() возвращает тот же экземпляр, когда вызываются из одной и той же транзакции. Я предполагаю, что в вашем случае настройка вашего теста не происходит в той же транзакции, что и метод тестирования, поэтому find() создает разные экземпляры.

+1

axtavt правильный. Когда EntityManager закрыт, связанный с ним контекст сохранения, это сбор мусора. Если ваш экземпляр EntityManager автоматически поставляется контейнером вместе с транзакцией, ваши вызовы в em.find() всегда возвращают один и тот же физический объект для того же первичного ключа, пока одна и та же транзакция (и EntityManager) все еще остается открытый. Если вам нужен EntityManager с более длительным сроком службы, тогда у вас есть возможность использовать управляемый приложениями EntityManager вместо управляемого контейнером, но с некоторой дополнительной работой. –

+0

Я вижу, спасибо за ваши ответы. Я уверен, что есть только одна транзакция, разделяемая как моим тестом, так и моим dao, поскольку методы, аннотированные @Before и @After, включены в аннотацию @Transactional; Журналы Toplink также показывают одну транзакцию. Поэтому, я думаю, я не должен получать тот же EntityManager как в тестовом классе, так и в DAO. Есть ли способ узнать, являются ли два EntityManager одинаковыми? Я знаю, что общий EntityManager, который дает мне Spring, фактически является прокси-сервером, который делегирует вызовы, поэтому я не вижу очевидного способа проверки. – Conan

+0

@Conan: Я проверил его и выяснил, что методы '@ Before' /' @ After' фактически выполняются в той же транзакции, что и '@ Test', поэтому' em.find() 'возвращает те же экземпляры. Возможно, ваша проблема имеет другую причину. Вы можете зарегистрировать 'TransactionSynchronizationManager.getCurrentTransactionName()' для проверки идентичности транзакции. – axtavt

0

Нет, это не так. В любом случае вы должны полагаться на объект EQUALITY, а не IDENTITY. Переопределить метод equals.

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