2

Can anyone give me an example of how to call DB transactions in scheduled tasks by using Spring Boot 1.4.2.RELEASE, please? Thank you very much.

I used Spring Boot 1.4.2.RELEASE to create a scheduled task through @Scheduled(fixedRate = 5000) @Transactional(propagation = Propagation.REQUIRES_NEW), and used @Autowired to get an instance of JpaRepository.

@Scheduled(fixedRate = 5000)
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void importDataFromDat() {
    List records = datUploadRecordRepository.findAllByImportTime();

    for (DatUploadRecord record : records) {

        record.setImportTime(new Date());
        datUploadRecordRepository.save(record);
  //    datUploadRecordRepository.updateImportTime(new Date(), record.getId());
    }
}
  1. It can return results of select SQL, but it cannot save entities to the DB.
  2. If I create my own update method in my own JpaRepository rather than calling the save() method, it will cause the bug below:

org.springframework.dao.InvalidDataAccessApiUsageException: Executing an update/delete query; nested exception is javax.persistence.TransactionRequiredException: Executing an update/delete query at org.springframework.orm.jpa.EntityManagerFactoryUtils.convertJpaAccessExceptionIfPossible(EntityManagerFactoryUtils.java:413) ~[spring-orm-4.3.4.RELEASE.jar:4.3.4.RELEASE] at org.springframework.orm.hibernate5.HibernateExceptionTranslator.translateExceptionIfPossible(HibernateExceptionTranslator.java:55) ~[spring-orm-4.3.4.RELEASE.jar:4.3.4.RELEASE] at org.springframework.dao.support.ChainedPersistenceExceptionTranslator.translateExceptionIfPossible(ChainedPersistenceExceptionTranslator.java:59) ~[spring-tx-4.3.4.RELEASE.jar:4.3.4.RELEASE] at org.springframework.dao.support.DataAccessUtils.translateIfNecessary(DataAccessUtils.java:213) ~[spring-tx-4.3.4.RELEASE.jar:4.3.4.RELEASE] at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:147) ~[spring-tx-4.3.4.RELEASE.jar:4.3.4.RELEASE] at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) ~[spring-aop-4.3.4.RELEASE.jar:4.3.4.RELEASE] at org.springframework.data.jpa.repository.support.CrudMethodMetadataPostProcessor$CrudMethodMetadataPopulatingMethodInterceptor.invoke(CrudMethodMetadataPostProcessor.java:133) ~[spring-data-jpa-1.10.5.RELEASE.jar:na] at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) ~[spring-aop-4.3.4.RELEASE.jar:4.3.4.RELEASE] at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:92) ~[spring-aop-4.3.4.RELEASE.jar:4.3.4.RELEASE] at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) ~[spring-aop-4.3.4.RELEASE.jar:4.3.4.RELEASE] at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:213) ~[spring-aop-4.3.4.RELEASE.jar:4.3.4.RELEASE] at com.sun.proxy.$Proxy112.updateImportTime(Unknown Source) ~[na:na] at com.crane.schedules.ImportToDBFromDAT.importDataFromDat(ImportToDBFromDAT.java:65) ~[classes/:na] at com.crane.schedules.ImportToDBFromDAT$$FastClassBySpringCGLIB$$847b3ccb.invoke() ~[classes/:na] at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204) ~[spring-core-4.3.4.RELEASE.jar:4.3.4.RELEASE] at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:720) ~[spring-aop-4.3.4.RELEASE.jar:4.3.4.RELEASE] at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157) ~[spring-aop-4.3.4.RELEASE.jar:4.3.4.RELEASE] at org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:99) ~[spring-tx-4.3.4.RELEASE.jar:4.3.4.RELEASE] at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:282) ~[spring-tx-4.3.4.RELEASE.jar:4.3.4.RELEASE] at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:96) ~[spring-tx-4.3.4.RELEASE.jar:4.3.4.RELEASE] at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) ~[spring-aop-4.3.4.RELEASE.jar:4.3.4.RELEASE] at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:655) ~[spring-aop-4.3.4.RELEASE.jar:4.3.4.RELEASE] at com.crane.schedules.ImportToDBFromDAT$$EnhancerBySpringCGLIB$$971e70c9.importDataFromDat() ~[classes/:na] at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_60] at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source) ~[na:1.8.0_60] at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source) ~[na:1.8.0_60] at java.lang.reflect.Method.invoke(Unknown Source) ~[na:1.8.0_60] at org.springframework.scheduling.support.ScheduledMethodRunnable.run(ScheduledMethodRunnable.java:65) ~[spring-context-4.3.4.RELEASE.jar:4.3.4.RELEASE] at org.springframework.scheduling.support.DelegatingErrorHandlingRunnable.run(DelegatingErrorHandlingRunnable.java:54) ~[spring-context-4.3.4.RELEASE.jar:4.3.4.RELEASE] at java.util.concurrent.Executors$RunnableAdapter.call(Unknown Source) [na:1.8.0_60] at java.util.concurrent.FutureTask.runAndReset(Unknown Source) [na:1.8.0_60] at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$301(Unknown Source) [na:1.8.0_60] at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(Unknown Source) [na:1.8.0_60] at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source) [na:1.8.0_60] at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source) [na:1.8.0_60] at java.lang.Thread.run(Unknown Source) [na:1.8.0_60] Caused by: javax.persistence.TransactionRequiredException: Executing an update/delete query at org.hibernate.jpa.spi.AbstractQueryImpl.executeUpdate(AbstractQueryImpl.java:54) ~[hibernate-entitymanager-5.0.11.Final.jar:5.0.11.Final] at org.springframework.data.jpa.repository.query.JpaQueryExecution$ModifyingExecution.doExecute(JpaQueryExecution.java:242) ~[spring-data-jpa-1.10.5.RELEASE.jar:na] at org.springframework.data.jpa.repository.query.JpaQueryExecution.execute(JpaQueryExecution.java:82) ~[spring-data-jpa-1.10.5.RELEASE.jar:na] at org.springframework.data.jpa.repository.query.AbstractJpaQuery.doExecute(AbstractJpaQuery.java:116) ~[spring-data-jpa-1.10.5.RELEASE.jar:na] at org.springframework.data.jpa.repository.query.AbstractJpaQuery.execute(AbstractJpaQuery.java:106) ~[spring-data-jpa-1.10.5.RELEASE.jar:na] at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.doInvoke(RepositoryFactorySupport.java:482) ~[spring-data-commons-1.12.5.RELEASE.jar:na] at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.invoke(RepositoryFactorySupport.java:460) ~[spring-data-commons-1.12.5.RELEASE.jar:na] at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) ~[spring-aop-4.3.4.RELEASE.jar:4.3.4.RELEASE] at org.springframework.data.projection.DefaultMethodInvokingMethodInterceptor.invoke(DefaultMethodInvokingMethodInterceptor.java:61) ~[spring-data-commons-1.12.5.RELEASE.jar:na] at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) ~[spring-aop-4.3.4.RELEASE.jar:4.3.4.RELEASE] at org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:99) ~[spring-tx-4.3.4.RELEASE.jar:4.3.4.RELEASE] at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:282) ~[spring-tx-4.3.4.RELEASE.jar:4.3.4.RELEASE] at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:96) ~[spring-tx-4.3.4.RELEASE.jar:4.3.4.RELEASE] at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) ~[spring-aop-4.3.4.RELEASE.jar:4.3.4.RELEASE] at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:136) ~[spring-tx-4.3.4.RELEASE.jar:4.3.4.RELEASE] ... 31 common frames omitted

Michael Petch
  • 46,082
  • 8
  • 107
  • 198
Belinda_Bin
  • 21
  • 1
  • 2
  • I'd say the update method on your repository need to be Transactional. Not the Scheduled task. – Jeremy Grand Feb 20 '17 at 13:27
  • Thank you for the reply. I made the update method be Transactional, but the result is the same as above. – Belinda_Bin Feb 20 '17 at 13:32
  • Has your Spring boot properly activated the transactional management ? (I.e. do you added the annotations `@EnableAutoConfiguration` `@EnableJpaRepositories` `@EnableTransactionManagement` in you configuration class ?) – Jeremy Grand Feb 20 '17 at 13:37
  • Yes, I did add these annotations in my DB configuration class and my application class. – Belinda_Bin Feb 20 '17 at 13:49
  • I am struggling with similar issue....need to update the db from scheduled task....and the scheduled task method is in service class.......see this question https://stackoverflow.com/questions/55792216/spring-boot-task-to-update-foreign-key-in-db?r=SearchResults – Akki Apr 23 '19 at 04:31

2 Answers2

0

Maybe late, but could you not create an independant transactional Component that manage the operation and then call it from the task?

In our application, we used a scheduled task to purge document. It call document service to get all the docs (transactional operation) and then purge each doc (purge method from document service is transactional too)

Mohicane
  • 302
  • 2
  • 15
0

I got such issue solved with wrapping the body of importDataFromDat() to a separate method annotated with @Transactional of another class and creating a method annotated with @Async that is called from importDataFromDat()

P.S. don't forget to add @EnableAsync to the configuration

Panz0r
  • 105
  • 1
  • 10