Hibernate не может найти сеанс, связанный с потоком при использовании @PostConstruct
Я переделываю старый проект Spring, чтобы больше отражать, как все должно быть сделано в Spring 3.0.x.
Одно из изменений, которые я сделал, было в уровне хранилища / дао. Согласно рекомендациям, я больше не HibernateDaoSupport
использовать HibernateTemplate
, но вместо этого я использую Hibernate SessionFactory
непосредственно с помощью sessionFactory.getCurrentSession()
, который должен работать с Spring 3.0.x и выше.
Это было очень большим благом для проекта в целом, поскольку оно избавляет от всего кода переноса, вызванного HibernateTemplate
, Однако я только что заметил, что больше не могу вызывать методы Service, которые использовали @PostConstruct (или использовали бин onStartUp
атрибут в контексте приложения XML)
Например, этот метод работал нормально, используя HibernateTemplate
, но теперь Hibernate выдает исключение, сообщающее, что с потоком не связан поток:
@Override
@PostConstruct
public void onStartUp() {
logger.debug("Starting Bootstrap Service...");
createSysAdminUser();
createDefaultRoles();
createDefaultThemes();
createStopListIfDoesNotExist();
stopListService.load();
partialMappingService.load();
dictionaryService.load();
}
Я мог бы просто удалить это @PostConstruct
вызов метода... он единственный в системе. Он вызывается, когда приложение запускается для загрузки данных для нового приложения. В большинстве случаев он ничего не делает в производственной системе, но удобно иметь его для тестовых и разработанных баз данных, которые были созданы заново.
Есть идеи, почему и как я могу это исправить?
Спасибо!
РЕДАКТИРОВАТЬ: Вот моя конфигурация совета управления транзакциями:
<aop:config>
<aop:advisor advice-ref="transactionAdvice"
pointcut="execution(* *..service.*.*(..))" order="1"/>
<!-- gets sub packages like service.user -->
<aop:advisor advice-ref="transactionAdvice"
pointcut="execution(* *..service.*.*.*(..))" order="2"/>
</aop:config>
<tx:advice id="transactionAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="find*" read-only="true" propagation="REQUIRED"/>
<tx:method name="get*" read-only="true" propagation="REQUIRED"/>
<tx:method name="*" propagation="REQUIRED"/>
</tx:attributes>
</tx:advice>
1 ответ
Как указано в документации к классу HibernateDaoSupport: "Этот класс создаст свой собственный экземпляр HibernateTemplate, если будет передан SessionFactory. Флаг allowCreate на этом HibernateTemplate будет иметь значение" true "по умолчанию". Это означает, что в старой системе ваши DAO могли открывать сессии по требованию, не находясь под каким-либо реальным контролем.
Когда Spring управляет SessionFactory, он устанавливает SpringSessionContext в качестве CurrentSessionContext Hibernate. Теперь, когда вы звоните SessionFactory.getCurrentSession()
SpringSessionContext ищет в ThreadLocal, управляемом Spring, для сеанса и завершается ошибкой, если его там нет. Сеанс обычно открывается и помещается туда одним из двух способов: использование шаблона open-session-in-view делает это при каждом новом запросе, и запуск транзакции также делает это. В вашем случае вы не выполняете код в ответ на запрос, поэтому OSIV не находится в игре, и вы, очевидно, также не участвуете в активной транзакции. Создание транзакционного метода позаботится о вашей проблеме.