(ancora un po 'nuova per primavera)Primavera: metodo @Transactional @Scheduled getta TransactionException
ho bisogno di avere un metodo di servizio che è allo stesso tempo @Scheduled
e @Transactional
, in modo che riesco a chiamare un DAO in esso.
Le transazioni dichiarative sono abilitate, il gestore transazioni è un org.springframework.orm.hibernate3.HibernateTransactionManager
basato su una factory di sessione di sospensione.
La classe di servizio non implementa alcuna interfaccia in modo da utilizzare un proxy CGLIB.
Questa configurazione funziona in generale (metodi chiamati dallo stack Web, cioè Struts) ma questo metodo solleva un'eccezione quando viene chiamato dallo scheduler.
Ecco i bit rilevanti di codice:
Il metodo di servizio (la classe si chiama 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
}
parti rilevanti del mio contesto di applicazione: pila
<!-- 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>
Eccezione traccia:
[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.access$301(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
La traccia dello stack sembra dirmi che un proxy transazionale è effettivamente utilizzato, quindi non capisco questa eccezione. Aiuto !
EDIT:
ho cercato di separare i @Transactional
ei @Scheduled
annotazioni da:
- creare una nuova classe/bean che contaisn il metodo
@Scheduled
- Iniettare il mio servizio a questo fagiolo
- Rimosso il
@Scheduled
dal metodo originale ma lasciato lo@Transactional
Ma ho ancora la stessa eccezione. Ho anche provato a mettere il @Transactional
sul mio metodo DAO e rimuoverlo dal mio metodo di servizio: stesso risultato.
questo può accadere quando si è già impegnata o rollback delle transazioni cerca di commit o rollback – wedens
è possibile mostrare il metodo di dao? – wedens
OK, il mio metodo DAO era il colpevole. Stavo iniziando a sospettare e poi il tuo commento mi ha fatto guardare due volte. Quindi il metodo conteneva alcuni commit di sessione manuali rimanenti (sto recentemente modernizzando e "innescando" questa app), quindi quando il proxy transazionale stava chiamando il commit falliva perché era già stato commesso! Grazie per il tuo tempo. Se modifichi la tua risposta per menzionare il metodo DAO, lo accetterò. –