Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Spring : @Transactional @Scheduled method throws TransactionException

(Still a bit new to 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.

Declarative transactions are enabled, the transaction manager is a org.springframework.orm.hibernate3.HibernateTransactionManager based on a hibernate session factory.

The service class does not implement any interface so a CGLIB proxy is used.

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.

Here are the relevant bits of code :

The service method (the class is called 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.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

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 :

  • 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

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.

like image 382
Pierre Henry Avatar asked Aug 23 '13 09:08

Pierre Henry


2 Answers

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.

EDIT: also look at your DAO method and make sure it not commits or rolls back transaction manually

like image 91
wedens Avatar answered Oct 12 '22 09:10

wedens


In my case

@EnableTransactionManagement

was not used. After I add this annotation to one of my @Configuration classes it start to work.

like image 33
degr Avatar answered Oct 12 '22 07:10

degr