2013-08-23 14 views
6

(Jeszcze trochę nowych do wiosny)Wiosna: metoda @Transactional @Scheduled rzuca TransactionException

muszę mieć metodę usług, które są jednocześnie @Scheduled i @Transactional, tak że mogę zadzwonić w DAO to.

Transakcje deklaracyjne są włączone, menedżer transakcji to org.springframework.orm.hibernate3.HibernateTransactionManager oparty na fabryce sesji hibernacji.

klasa Usługa nie realizuje żadnego interfejsu tak jest używany serwer proxy CGLIB.

Układ ten działa dobrze w ogóle (metody wywoływane z sieci stos czyli poprzeczne), ale sposób ten zwiększa się wyjątek, kiedy wywoływana przez planistę.

Oto stosowne fragmenty kodu:

Metoda service (klasa nazywa 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 

    } 

Istotne części mojego kontekście aplikacji:

<!-- 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> 

Wyjątek stosu ślad:

[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 

Stos ślad Wydaje mi powiedzieć, że transakcyjny proxy jest rzeczywiście używany więc nie rozumiem tego wyjątku. Wsparcie !

EDIT:

starałem się oddzielić @Transactional i @Scheduled adnotacji przez:

  • utworzyć nową klasę/Fasola że contaisn the metoda @Scheduled
  • wstrzyknąć moją służbę do tej fasoli
  • Usunięto @Scheduled z mojej oryginalnej metodzie ale opuścił @Transactional

Ale nadal uzyskać ten sam wyjątek. Próbowałem również umieścić @Transactional w mojej metodzie DAO i usunąć ją z mojej metody serwisowej: ten sam wynik.

+0

może się to zdarzyć, gdy już zaangażowani lub wycofana transakcja próbuje popełnić lub wycofania – wedens

+0

można pokazać swoją metodę dao? – wedens

+1

OK, moja metoda DAO była winna. Zaczynałem podejrzewać to i wtedy twój komentarz sprawił, że spojrzałem dwa razy. Metoda zawierała więc ręczny commit sesji po lewej stronie (ostatnio aktualizuję i "tworzę" tę aplikację), więc gdy transakcyjny serwer proxy wywoływał zatwierdzenie, nie udało się, ponieważ został już zatwierdzony! Dziękuję za Twój czas. Jeśli edytujesz swoją odpowiedź, by wspomnieć o metodzie DAO, przyjmuję ją. –

Odpowiedz

11

utwórz oddzielną klasę metodą oznaczoną @Transactional i wywołaj tę metodę w swojej opisanej metodzie @Scheduled. wiosna wykona połączenie za pośrednictwem serwera proxy i poprawnie obsłuży numer @Transactional.

EDIT: również spojrzeć na metody DAO i upewnić się, że nie popełnia albo wycofuje transakcję ręcznie

+0

Dzięki, zrobiłem to, ale dostaję ten sam błąd (patrz edytuj) –

+0

Dzięki @wedens za tę odpowiedź, to działa dla mnie. Możesz wyjaśnić, dlaczego nie działa, gdy metoda jest w tej samej klasie. – hayat

+0

Wiem, bardzo stary post, ale nie cierpię zostawiać tego pytania. Przyczyną jest sposób działania proxy. Najprostszą odpowiedzią jest to, że może zobaczyć, co nadchodzi i wychodzi, ale nie to, co dzieje się wewnątrz. Jest to spowodowane charakterem proxy. – Wes

Powiązane problemy