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 не находится в игре, и вы, очевидно, также не участвуете в активной транзакции. Создание транзакционного метода позаботится о вашей проблеме.

Другие вопросы по тегам