Почему требуется Entity Manager clear()? - Spring3 @Transactional, JPA2/Hibernate3

У меня есть приложение JSF2, использующее JPA2/Hibernate с Spring @Transactional. В пользовательском интерфейсе нет операторов @Transactional (бэк-бины), только на уровне сервиса. (Я использую @Transactional(propagation=Propagation.MANDATORY) в DAO, чтобы убедиться, что каждый вызов происходит в транзакции.) Все работает очень хорошо, за исключением...

Когда я открываю и обновляю объекты с помощью методов транзакционной службы, иногда полученные объекты устаревают. Неважно, что это один и тот же пользователь в том же сеансе, иногда методы «чтения» JPA возвращают старые устаревшие объекты, которые (должны были) уже быть заменены. Это поставило меня в тупик на некоторое время, но оказалось, что это вызвано кэшированием в Entity Manager. DAO аннотируются @Repository, поэтому внедренный EntityManager используется повторно. Я ожидал, что когда транзакция завершится, диспетчер сущностей будет автоматически очищен. Но это не тот случай. Обычно Entity Manager возвращает правильное значение, но часто он возвращается и вместо этого возвращает старое значение из более ранней транзакции.

В качестве обходного пути я добавил стратегические операторы entityManager.clear() в методы чтения DAO, но это уродливо. Менеджеры сущностей должны очищаться после каждой транзакции.

Кто-нибудь испытал это? Есть ли правильное решение? Можно ли очищать диспетчер объектов после каждой транзакции?

Большое спасибо.

Я использую: org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean и org.springframework.orm.jpa.JpaTransactionManager


person John    schedule 10.09.2012    source источник


Ответы (2)


Аннотация @Transactional существует на уровне службы. Методы службы, помеченные @Transactional, будут придерживаться свойств ACID независимо от того, сколько вызовов DAO выполняется внутри него.

Это означает, что вам не нужно аннотировать методы DAO как @Transactional.

Я работаю над чем-то подобным, и вот как я это сделал, и мои данные согласуются.

Попробуйте это и посмотрите, по-прежнему ли вы получаете противоречивые данные.

person Arun Padmanabhan    schedule 11.09.2012
comment
Я хочу убедиться, что если один из методов DAO когда-либо вызывается напрямую, вне существующей транзакции, возникает исключение. DAO никогда не должны начинать транзакцию. Я думал, что это сделает @Transactional(propagation=Propagation.MANDATORY). - person John; 12.09.2012
comment
DAO никогда не должны вызываться напрямую. Уровень обслуживания обращается к уровню DAO. Контроллер/конечная точка должны получить доступ к сервисному уровню. Так зачем думать о том, что DAO вызываются напрямую. Уровень службы будет вызывать DAO. - person Arun Padmanabhan; 12.09.2012
comment
Также он ведет себя так же, если в DAO добавляется только @Transactional, то есть без propagation=Propagation.MANDATORY. - person Arun Padmanabhan; 12.09.2012
comment
Распространение по умолчанию ТРЕБУЕТСЯ, что может привести к созданию транзакций в DAO. Я не хочу этого делать. - person John; 12.09.2012

Используете ли вы аннотацию @PersistenceContext (выше EntityManager в DAO) в сочетании с компонентом PersistenceAnnotationBeanPostProcessor (вам не нужно определять компонент PersistenceAnnotationBeanPostProcessor, если вы используете теги <context:annotation-config/> и <context:component-scan/> XML)? Если нет, то я думаю, что это причина ваших проблем.

person Tomasz Szymulewski    schedule 20.08.2014