9

SpringBoot 1.4.1.RELEASE is used. A simple task is create that runs every 5 seconds. It fetched data from database using Spring Data JPA, sends the data through an API and on success, updates send status in database using Spring Data JPA.

Following is scheduler code snippet

@Component
public class MemberJob {
    @Value("${base.url}")
    private String baseApiUrl;

    @Autowired
    private RestTemplate restTemplate;

    @Autowired
    @Qualifier("memberServiceBean")
    private EntityService memberServiceBean;

    @Scheduled(fixedDelay = 5000l)
    public void runJob() throws Exception {
         Collection<Member> notSynched = memberRepository.findAll();
         notSynched.stream().forEach(m -> {
                //Send to server: on success
                m.setSyncStatus(true);
                memberServiceBean.update(m);
         });
    }
}

The problem is on success the member is not updated.For some reasons Spring Data JPA is not working in @Scheduled method. How can i make data jpa update this object inside self-invocation @Scheduled method?

And yes the update method in service layer is decorated with @Transactional like so

@Transactional(propagation = Propagation.REQUIRED)
public Member update(Member m) {
    return (Member) getRepository().save(m);
}

Update

Based on suggestions on comment section, update method is surrounded by try/catch unfortunate no exception was caught! Like so

 try{
     m = (Member) memberServiceBean.update(m);
 }catch(Exception ex){
     ex.printStackTrace();
 }

Also in application.properties file, logging.level.org.springframework.transaction.interceptor=TRACE was added and following trace seen

2017-10-07 11:23:21.968 TRACE 2200 --- [ask-scheduler-3] o.s.t.i.TransactionInterceptor           : Getting transaction for [re.iprocu.service.impl.MemberServiceBean.update]
2017-10-07 11:23:21.969 TRACE 2200 --- [ask-scheduler-3] o.s.t.i.TransactionInterceptor           : Getting transaction for [org.springframework.data.jpa.repository.support.QueryDslJpaRepository.save]
2017-10-07 11:23:22.536 TRACE 2200 --- [ask-scheduler-3] o.s.t.i.TransactionInterceptor           : Completing transaction for [org.springframework.data.jpa.repository.support.QueryDslJpaRepository.save]
2017-10-07 11:23:22.536 TRACE 2200 --- [ask-scheduler-3] o.s.t.i.TransactionInterceptor           : Completing transaction for [re.iprocu.service.impl.MemberServiceBean.update]

Still no update to database is realized. If any additional information needed, please don't hesitate to ask.

Update 2

Respository save if changed to saveAndFlush following exception is caught

org.springframework.dao.InvalidDataAccessApiUsageException: no transaction is in progress; nested exception is javax.persistence.TransactionRequiredException: no transaction is in progress
at org.springframework.orm.jpa.EntityManagerFactoryUtils.convertJpaAccessExceptionIfPossible(EntityManagerFactoryUtils.java:413)
at org.springframework.orm.jpa.vendor.HibernateJpaDialect.translateExceptionIfPossible(HibernateJpaDialect.java:246)
at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.translateExceptionIfPossible(AbstractEntityManagerFactoryBean.java:491)
at org.springframework.dao.support.ChainedPersistenceExceptionTranslator.translateExceptionIfPossible(ChainedPersistenceExceptionTranslator.java:59)
at org.springframework.dao.support.DataAccessUtils.translateIfNecessary(DataAccessUtils.java:213)
at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:147)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.data.jpa.repository.support.CrudMethodMetadataPostProcessor$CrudMethodMetadataPopulatingMethodInterceptor.invoke(CrudMethodMetadataPostProcessor.java:133)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:92)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:213)
at com.sun.proxy.$Proxy209.saveAndFlush(Unknown Source)
at re.iprocu.service.impl.AbstractFacade.update(AbstractFacade.java:55)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:333)
at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:190)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157)
at org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:99)
at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:281)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:96)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:213)
at com.sun.proxy.$Proxy237.update(Unknown Source)
at re.iprocu.job.iprocuredata.MemberJob.lambda$runJob$0(MemberJob.java:104)
at java.util.ArrayList$ArrayListSpliterator.forEachRemaining(ArrayList.java:1374)
at java.util.stream.ReferencePipeline$Head.forEach(ReferencePipeline.java:580)
at re.iprocu.job.iprocuredata.MemberJob.runJob(MemberJob.java:59)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.springframework.scheduling.support.ScheduledMethodRunnable.run(ScheduledMethodRunnable.java:65)
at org.springframework.scheduling.support.DelegatingErrorHandlingRunnable.run(DelegatingErrorHandlingRunnable.java:54)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
at java.util.concurrent.FutureTask.runAndReset(FutureTask.java:308)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$301(ScheduledThreadPoolExecutor.java:180)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:294)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:745)
Caused by: javax.persistence.TransactionRequiredException: no transaction is in progress
at org.hibernate.jpa.spi.AbstractEntityManagerImpl.checkTransactionNeeded(AbstractEntityManagerImpl.java:1136)
at org.hibernate.jpa.spi.AbstractEntityManagerImpl.flush(AbstractEntityManagerImpl.java:1297)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.springframework.orm.jpa.ExtendedEntityManagerCreator$ExtendedEntityManagerInvocationHandler.invoke(ExtendedEntityManagerCreator.java:347)
at com.sun.proxy.$Proxy171.flush(Unknown Source)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.springframework.orm.jpa.SharedEntityManagerCreator$SharedEntityManagerInvocationHandler.invoke(SharedEntityManagerCreator.java:298)
at com.sun.proxy.$Proxy171.flush(Unknown Source)
at org.springframework.data.jpa.repository.support.SimpleJpaRepository.flush(SimpleJpaRepository.java:553)
at org.springframework.data.jpa.repository.support.SimpleJpaRepository.saveAndFlush(SimpleJpaRepository.java:521)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.executeMethodOn(RepositoryFactorySupport.java:503)
at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.doInvoke(RepositoryFactorySupport.java:488)
at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.invoke(RepositoryFactorySupport.java:460)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.data.projection.DefaultMethodInvokingMethodInterceptor.invoke(DefaultMethodInvokingMethodInterceptor.java:61)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:99)
at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:281)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:96)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:136)
... 38 more
Yunus Einsteinium
  • 1,102
  • 4
  • 21
  • 55
  • What's the exception that u are getting ? – db80 Oct 06 '17 at 09:24
  • No any exception is thrown, it just doesn't update – Yunus Einsteinium Oct 06 '17 at 09:27
  • You are not modifying the object "Member m" after reading it. It seems you are saving the same object that you have just read. – db80 Oct 06 '17 at 09:30
  • Actually i'm changing status, i just didn't show it initially in my question. Now it's there – Yunus Einsteinium Oct 06 '17 at 09:33
  • Exceptions thrown in a forEach lamba are eaten. Put a try/catch around the ``memberServiceBean.update()`` call to see if it is throwing. – brettw Oct 06 '17 at 16:50
  • @brettw updated post with your suggestions and others – Yunus Einsteinium Oct 07 '17 at 09:24
  • do you have enabled jpa logs? Add this property to application.properties file `spring.jpa.show-sql=true` and look whats happen. – Patrick Oct 09 '17 at 06:43
  • @Patrick when `spring.jpa.show-sql=true` added, only `select` statements are seen, no `update` or `insert` statement seen – Yunus Einsteinium Oct 09 '17 at 06:59
  • so it seems that you really dont make an update. Are you really sure that you change properties of your entity. try to change another property instead of your boolean one – Patrick Oct 09 '17 at 07:04
  • @Patrick, also change another integer property but nothing changed in db. Though when changed `save` to `saveAndFlush` an exception is thrown, check post update 2 – Yunus Einsteinium Oct 09 '17 at 07:21
  • It seems, the transaction is not available when executed the persistence operation. Do you tried the solution in [this topic](https://stackoverflow.com/questions/5443876/spring3-s-transactional-scheduled-not-committed-to-db)? use a `TransactionTemplate` to execute a manual transaction. – Hantsy Oct 09 '17 at 09:48
  • @Hantsy i have done that, no change, same exception is thrown – Yunus Einsteinium Oct 09 '17 at 10:06
  • Another possible solution, switch transaction AOP to AspectJ from JDK proxy. I have encountered the similar problem in before projects, but now I can not remember the exact case. Most of time, I would like to use AspectJ to weave transaction/cache etc, and it also support compile time weaving. – Hantsy Oct 09 '17 at 13:39
  • @Hantsy If i change AOP to AspectJ will it have a ripple effect to service layer transactions? – Yunus Einsteinium Oct 09 '17 at 13:45
  • did you try, Propagation REQUIRES_NEW ? – Makoton Oct 11 '17 at 14:15
  • I'm running into this same issue... nested exception is javax.persistence.TransactionRequiredException: no transaction is in progress Have you resolved this issue without the jdbctemplate? Weird as @Transactional should just work – Multiplexor Nov 19 '17 at 06:23
  • @Multiplexor: No i just went on with jdbcTemplate, though i would appreciate to know the solution – Yunus Einsteinium Nov 19 '17 at 07:00

2 Answers2

1

I had the same issue. Resolved it with including something like this in my @Repository interface:

@Modifying
@Query("update coop_member set sync_status = :syncStatus where member_id = :memberId")
void updateSyncStatus(Long memberId, boolean syncStatus);

Variable names and types could be different, but the important part was using the @Modifying and the @Query annotations.

It also assumes marking with @Transactional and @EnableScheduling. None of the entity manager flushing/merging or setting propagation/isolation on the transaction worked. Call that method instead of save().

riddle_me_this
  • 8,575
  • 10
  • 55
  • 80
0

As there is no answer that fixed my saving issue in @Scheduler self-invocation method, i decided to use JdbcTemplate which does work.

 jdbcTemplate.update("UPDATE coop_member SET sync_status = ? WHERE member_id = ?", uMember.getSyncStatus(), uMember.getMemberId());

In my case i only want to update sync_status so it not alot of work.

Yunus Einsteinium
  • 1,102
  • 4
  • 21
  • 55