问题
In the following schema
Controller -> Service -> DAO I'm trying to make Service operations @Transactional
in my UserService.fooFunction() i call
Entity e = dao.find(key)
e.setProperty(something)
dao.update(e)
in dao.update(e) at the end there is
em.flush() //EntityManager obtained by @PersistenceContext annotation (injected by spring IoC)
Calling flush() throws a 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)
I'm running low on ideas what I've done wrong, any help would be appreciated :)
You can find chunks of my configuration below:
<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 part:
<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>
no transactional annotations are present. When deploying my spring app one can see
[<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]
回答1:
Key problem was here
tx:annotation-driven only looks for @Transactional on beans in the same application context it is defined in. This means that, if you put in a WebApplicationContext for a DispatcherServlet, it only checks for @Transactional beans in your controllers, and not your services. See Section 15.2, “The DispatcherServlet” for more information.
Putting i the same application context as component-scan for services solved the problem :)
回答2:
You declared JtaTransactionManager
as your transaction manager. Are you sure your program is running in JTA-capable environment, such as a full-blown application server (JBoss, WebSphere, WebLogic, etc)?
If you don't have JTA environment, you need to use JPATransactionManager
instead:
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory"/>
</bean>
来源:https://stackoverflow.com/questions/5220125/spring-transactional-javax-persistence-transactionrequiredexception