Spring @Transactional — javax.persistence.TransactionRequiredException

В следующей схеме

Контроллер -> Служба -> DAO Я пытаюсь выполнить операции службы @Transactional

в моем UserService.fooFunction() я вызываю

Entity e = dao.find(key)
e.setProperty(something)
dao.update(e)

в dao.update(e) в конце есть

em.flush() //EntityManager obtained by @PersistenceContext annotation (injected by spring IoC)

Вызов flush() вызывает исключение persistenceException:

javax.persistence.TransactionRequiredException No externally managed transaction is currently active for this thread
    at org.eclipse.persistence.internal.jpa.transaction.JTATransactionWrapper.throwCheckTransactionFailedException(JTATransactionWrapper.java:86)

У меня заканчиваются идеи, что я сделал неправильно, любая помощь будет оценена :)

Вы можете найти фрагменты моей конфигурации ниже:

 <bean id="entityManagerFactory"  class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
    <property name="dataSource" ref="dataSource"/>
    <property name="persistenceUnitName" value="myPU" />
    <property name="jpaVendorAdapter">
        <bean class="org.springframework.orm.jpa.vendor.EclipseLinkJpaVendorAdapter" id="eclipselinkVendorAdapter">
        ..
        </bean>
    </property>

</bean>

<bean id="transactionManager" class="org.springframework.transaction.jta.JtaTransactionManager">

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

ап часть:

    <aop:config>

    <aop:pointcut id="userServiceOperation"
      expression="execution(* org.mypackage.UserServiceImpl.*(..))"/>

    <aop:advisor pointcut-ref="userServiceOperation" advice-ref="txUserServiceAdvice"/>

</aop:config>

<tx:advice id="txUserServiceAdvice">
    <tx:attributes>
        <tx:method name="get*" read-only="true" propagation="REQUIRES_NEW"/>
        <tx:method name="update*" read-only="false" propagation="REQUIRES_NEW"/>
        <tx:method name="*" propagation="REQUIRES_NEW"/>
    </tx:attributes>
</tx:advice>

транзакционных аннотаций нет. При развертывании моего весеннего приложения можно увидеть

[<date>] DEBUG support.DefaultListableBeanFactory: Returning cached instance of singleton bean 'org.springframework.transaction.config.internalTransactionAdvisor'
[<date>] DEBUG interceptor.NameMatchTransactionAttributeSource: Adding transactional method [get*] with attribute [PROPAGATION_REQUIRES_NEW,ISOLATION_DEFAULT,readOnly]
[<date>] DEBUG interceptor.NameMatchTransactionAttributeSource: Adding transactional method [update*] with attribute [PROPAGATION_REQUIRES_NEW,ISOLATION_DEFAULT]
[<date>] DEBUG interceptor.NameMatchTransactionAttributeSource: Adding transactional method [*] with attribute [PROPAGATION_MANDATORY,ISOLATION_DEFAULT]

person Jan    schedule 07.03.2011    source источник


Ответы (2)


Ключевая проблема была здесь

tx:annotation-driven ищет @Transactional только в bean-компонентах в том же контексте приложения, в котором он определен. Это означает, что если вы поместите WebApplicationContext для DispatcherServlet, он будет проверять только @Transactional bean-компоненты в ваших контроллерах, а не в вашем Сервисы. См. Раздел 15.2, «Сервлет DispatcherServlet» для получения дополнительной информации.

Помещение того же контекста приложения, что и сканирование компонентов для сервисов, решило проблему :)

person Jan    schedule 07.03.2011

Вы объявили JtaTransactionManager своим менеджером транзакций. Вы уверены, что ваша программа работает в JTA-совместимой среде, такой как полноценный сервер приложений (JBoss, WebSphere, WebLogic и т. д.)?

Если у вас нет среды JTA, вместо этого вам нужно использовать JPATransactionManager:

<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
    <property name="entityManagerFactory" ref="entityManagerFactory"/>
</bean>
person axtavt    schedule 07.03.2011
comment
Да, я запускаю это приложение на сервере приложений Sun Glassfish. Считаю свою проблему решенной :) Спасибо за ответ! - person Jan; 07.03.2011