Java Spring:@Transactional @Scheduled 方法抛出 TransactionException
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/18399006/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Spring : @Transactional @Scheduled method throws TransactionException
提问by Pierre Henry
(Still a bit new to Spring)
(对 Spring 来说还是有点新的)
I need to have a service method that is at the same time @Scheduled
and @Transactional
, so that I get to call a DAO in it.
我需要的是在同一时间,服务方法@Scheduled
和@Transactional
,让我得到调用DAO在里面。
Declarative transactions are enabled, the transaction manager is a org.springframework.orm.hibernate3.HibernateTransactionManager
based on a hibernate session factory.
声明式事务启用,事务管理器是一个org.springframework.orm.hibernate3.HibernateTransactionManager
基于休眠会话工厂。
The service class does not implement any interface so a CGLIB proxy is used.
服务类没有实现任何接口,因此使用了 CGLIB 代理。
This setup works fine in general (methods called from the web stack i.e. Struts) but this method raises an exception when called by the scheduler.
这种设置通常工作正常(从 Web 堆栈调用的方法,即 Struts),但是当被调度程序调用时,此方法会引发异常。
Here are the relevant bits of code :
以下是相关的代码位:
The service method (the class is called ClientWakeAndTerminateManager
) :
服务方法(类被调用ClientWakeAndTerminateManager
):
@Scheduled(initialDelay = 5000, fixedRateString = "${rmi.server.threads.clientsScheduleManagement.rate}")
@Transactional(readOnly = true)
public void runCheck(){
//Call a read-only DAO method (the DAO is @Autowired as a class field)
//do some stuff with the data loaded from DB
}
Relevant parts of my application context :
我的应用程序上下文的相关部分:
<!-- switch on the transactional infrastructure -->
<tx:annotation-driven transaction-manager="transactionManager" proxy-target-class="true"/>
<!-- Utility class to execute transactional code where use of annotation is not possible -->
<bean class="org.springframework.transaction.support.TransactionTemplate" id="txTemplate">
<constructor-arg name="transactionManager" ref="transactionManager"/>
</bean>
<!-- Transaction manager based on Hibernate -->
<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="hibernateSessionFactory"/>
</bean>
Exception stack trace :
异常堆栈跟踪:
[ERROR] : Unexpected error occurred in scheduled task.
org.springframework.transaction.TransactionSystemException: Could not commit Hibernate transaction; nested exception is org.hibernate.TransactionException: Transaction not successfully started
at org.springframework.orm.hibernate3.HibernateTransactionManager.doCommit(HibernateTransactionManager.java:661)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.processCommit(AbstractPlatformTransactionManager.java:755)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:724)
at org.springframework.transaction.interceptor.TransactionAspectSupport.commitTransactionAfterReturning(TransactionAspectSupport.java:475)
at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:270)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:94)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:631)
at ch.unine.sitel.lis.rmi.shared.ClientWakeAndTerminateManager$$EnhancerByCGLIB$$d8be4f34.runCheck(<generated>)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:601)
at org.springframework.scheduling.support.ScheduledMethodRunnable.run(ScheduledMethodRunnable.java:64)
at org.springframework.scheduling.support.DelegatingErrorHandlingRunnable.run(DelegatingErrorHandlingRunnable.java:53)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:471)
at java.util.concurrent.FutureTask$Sync.innerRunAndReset(FutureTask.java:351)
at java.util.concurrent.FutureTask.runAndReset(FutureTask.java:178)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access1(ScheduledThreadPoolExecutor.java:178)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:293)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1110)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:603)
at java.lang.Thread.run(Thread.java:722)
Caused by: org.hibernate.TransactionException: Transaction not successfully started
at org.hibernate.transaction.JDBCTransaction.commit(JDBCTransaction.java:127)
at org.springframework.orm.hibernate3.HibernateTransactionManager.doCommit(HibernateTransactionManager.java:657)
... 22 more
The stack trace seems to tell me that a transactional proxy is indeed used so I don't understand this exception. Help !
堆栈跟踪似乎告诉我确实使用了事务代理,所以我不明白这个异常。帮助 !
EDIT:
编辑:
I tried to separate the @Transactional
and the @Scheduled
annotations by :
我试图通过以下方式将@Transactional
和@Scheduled
注释分开:
- Create a new class/bean that contaisn the
@Scheduled
method - Inject my service to this bean
- Removed the
@Scheduled
from my original method but left the@Transactional
- 创建一个包含该
@Scheduled
方法的新类/bean - 将我的服务注入到这个 bean
@Scheduled
从我原来的方法中删除了,但留下了@Transactional
But I still get the same exception. I also tried to put the @Transactional
on my DAO method and remove it from my service method : same result.
但我仍然得到同样的例外。我还尝试将 放在@Transactional
我的 DAO 方法上并将其从我的服务方法中删除:结果相同。
采纳答案by wedens
create separate class with method annotated with @Transactional
and call this method in your @Scheduled
annotated method. spring will do a call through proxy and handle @Transactional
correctly.
使用注释的方法创建单独的类,@Transactional
并在您的@Scheduled
注释方法中调用此方法。spring 将通过代理进行调用并@Transactional
正确处理。
EDIT: also look at your DAO method and make sure it not commits or rolls back transaction manually
编辑:还要查看您的 DAO 方法并确保它不会手动提交或回滚事务
回答by degr
In my case
就我而言
@EnableTransactionManagement
was not used. After I add this annotation to one of my @Configuration classes it start to work.
没有使用。在我将此注释添加到我的 @Configuration 类之一后,它开始工作。