Почему Spring Transaction Management не работает с этой конфигурацией?

На SO ужасно много вопросов по этому поводу, но я попробовал некоторые из них, которые звучат правильно, но я все еще получаю

org.hibernate.HibernateException: No Session found for current thread

Классы уровня My Service аннотированы следующим образом:

   @Service
   public class MyService {
       @Autowired
       public SomeDao someDao;

       @Transactional
       public void performSomeTransaction() {/* ... */}
   }

XML контекста моего приложения имеет следующие релевантные объявления:

    <context:component-scan base-package = "com.myapp.business.dao.impl" />
    <context:component-scan base-package = "com.myapp.business.services" />

    <context:annotation-config />

    <tx:annotation-driven transaction-manager = "transactionManager" />

    <!-- Hibernate -->
    <bean id="sessionFactory"
        class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
        <property name="hibernateProperties">
            <props>
                <prop key="connection.url">jdbc:mysql://localhost:3306/bidapp</prop>
                <prop key="connection.username">bidapp</prop>
                <prop key="connection.password">pennyfss</prop>
                <prop key="connection.driver_class">com.mysql.jdbc.Driver</prop>

                <prop key="hibernate.connection.pool_size">10</prop>
                <prop key="hibernate.connection.autocommit">false</prop>
                <prop key="hibernate.dialect">org.hibernate.dialect.MySQL5InnoDBDialect</prop>
                <prop key="hibernate.show_sql">true</prop>
                <prop key="hibernate.hbm2ddl.auto">update</prop>

                <prop key="c3p0.acquireIncrement">1</prop>
                <prop key="c3p0.max_size">50</prop>
                <prop key="c3p0.max_statement">0</prop>
                <prop key="c3p0.min_size">10</prop>
                <prop key="c3p0.timeout">0</prop>
            </props>
        </property>
        <property name="dataSource" ref="dataSource"></property>
        <property name="packagesToScan">
            <list>
                <value>com.bidapp.business.domain</value>
            </list>
        </property>
    </bean>

    <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
        <property name="driverClassName" value="com.mysql.jdbc.Driver" />
        <property name="url" value="jdbc:mysql://localhost:3306/bidapp" />
        <property name="username" value="bidapp" />
        <property name="password" value="pennyfss" />
    </bean>

    <bean id="transactionManager"
        class="org.springframework.orm.hibernate4.HibernateTransactionManager">
        <property name="sessionFactory" ref="sessionFactory" />
    </bean>

У меня также есть файл dispatcher-servlet.xml с

    <mvc:annotation-driven />
<mvc:default-servlet-handler />

<context:component-scan base-package="com.myapp.presentation.controllers" />
<context:annotation-config />

<bean id="viewResolver" class="org.thymeleaf.spring3.view.ThymeleafViewResolver">
    <property name="templateEngine" ref="templateEngine" />
</bean>

Почему spring не обертывает мои услуги транзакциями?

Таким образом, похоже, что проблема связана с неправильным получением экземпляров. У меня есть следующая конфигурация Shiro Security:

    <bean id = "hibernateRealm" class = "com.bidapp.presentation.shiro.HibernateRealm" >
        <property name = "credentialsMatcher" ref = "credentialsMatcher" />
    </bean> 

    <bean id = "credentialsMatcher" class = "com.bidapp.presentation.shiro.JasyptCredentialsMatcher" />

    <bean id = "securityManager" class = "org.apache.shiro.web.mgt.DefaultWebSecurityManager">
        <property name = "realm" ref = "hibernateRealm" />
    </bean>

HibernateRealm — это сервисный класс с аннотацией @Transactional. Разве Spring не должен оборачивать его в прокси-сервер, поскольку он создает его здесь.


person Sotirios Delimanolis    schedule 25.01.2013    source источник


Ответы (2)


Наиболее распространенными причинами этой проблемы являются

  1. Неправильное получение экземпляра службы: например, его создание самостоятельно, а не получение экземпляра из Spring.
  2. Неправильная настройка контекстов корневого и дочернего приложений в приложении Spring MVC. Здесь я ответил на многие из этих вопросов. Вот некоторые из наиболее образовательных:

Справка/объяснение по иерархии файлов Spring XML

Объявление Spring Bean в родительском контексте по сравнению с дочерним контекстом < /а>

Показ кода, в котором вы получаете и используете экземпляр службы, поможет определить проблему.

person Ryan Stewart    schedule 25.01.2013
comment
Я почти уверен, что это связано с 1. Я использую безопасность shiro и объявляю службу компонента для ссылки в одном из менеджеров безопасности. Есть ли обходной путь для этого? - person Sotirios Delimanolis; 25.01.2013
comment
Я вводил DAO в свой класс Realm. После ваших указаний я автоматически подключил класс обслуживания, который вызывает DAO. Он помечен как транзакционный, поэтому я получаю такое же поведение за дополнительную плату. Ничего страшного. Оно работает. - person Sotirios Delimanolis; 25.01.2013

Добавьте свойство hibernate.current_session_context_class=thread во время создания фабрики сеансов в файле hibernate-persistance.xml, это будет работать.

person vipal kaila    schedule 16.10.2016
comment
Можете ли вы добавить дополнительную информацию о том, почему это работает, и, возможно, добавить пример в контексте? - person Friedrich 'Fred' Clausen; 17.10.2016
comment
Это связано с тем, что после добавления этого свойства hibernate.current_session_context_class=thread вы говорите, что hibernate предоставляет мне объект сеанса, привязанный к каждому потоку, когда вызывается sessionFactory.getCurrentSession(). Это нам нужно предоставить во время создания sessionFactory, и мы используем sessionFactory в качестве зависимости в TransactionManager Bean для управления нашими транзакциями. Spring создает transactionalProxy один раз в потоке. - person vipal kaila; 24.09.2018