0

I have a Spring boot app which has AggService in which I'm trying to save list of Agg with below mapping to Resource. I'm not modifying anything in Resource in the service. This service is marked with Spring's Scheduled annotation. The same service can be invoked via Rest endpoint as well.

Problem

If the service is invoked via rest endpoint, It runs fine. When the same service is kicked in by Scheduler, I'm getting the below exception.

Points to note

  • I'm not using any Transaction Management so far.
  • Since, I'm not modifying Resource in this service, I can remove CascadeType.All. But I wanted to know the reason why it runs fine when invoked via endpoint but not when run via Spring Scheduler.

Could someone help me to understand whats going on? Is transaction management should be enabled when scheduling is used?

Agg Entity

@Entity
@Table(name = "agg_name")
public class Agg {

    @Id
    @SequenceGenerator(name = "seq-gen", sequenceName = "agg_seq")
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "seq-gen")
    @Column(name = "id")
    private int id;

    @ManyToOne(fetch = FetchType.LAZY, cascade = { CascadeType.ALL })
    @JoinColumn(name = "resource_id")
    private Resource resource;

    ... 

}

Resource Entity

@Entity
@Table(name = "resource_table")
public class Resource {

    @Id
    @SequenceGenerator(name = "seq-gen", sequenceName = "resource_seq")
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "seq-gen")
    @Column(name = "id")
    private int id;

    @OneToMany(fetch = FetchType.LAZY, mappedBy = "resource")
    private List<Agg> aggs;

    ... 
    }

AggService

@Service
public class AggService {

    @Autowired
    private AggRepository aggRepository;

    @Scheduled(cron = "cron_expression")
    public void cPh(){
    List<Agg> aggList; // This list of Agg is being saved in line 150

    aggRepository.save(aggList); //line 150. Exception is thrown when trying to save

    }
}

Stacktrace when service is invoked by Scheduler

ERROR 8 --- [pool-2-thread-1] o.s.s.s.TaskUtils$LoggingErrorHandler    : Unexpected error occurred in scheduled task. 
  org.springframework.dao.InvalidDataAccessApiUsageException: detached entity passed to persist: c.g.r.e.Resource; nested exception is org.hibernate.PersistentObjectException: detached entity passed to persist: c.g.r.e.Resource 
    at org.springframework.orm.jpa.vendor.HibernateJpaDialect.convertHibernateAccessException(HibernateJpaDialect.java:299) ~[spring-orm-4.3.10.RELEASE.jar!/:4.3.10.RELEASE] 
    at org.springframework.orm.jpa.vendor.HibernateJpaDialect.translateExceptionIfPossible(HibernateJpaDialect.java:244) ~[spring-orm-4.3.10.RELEASE.jar!/:4.3.10.RELEASE] 
    at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.translateExceptionIfPossible(AbstractEntityManagerFactoryBean.java:488) ~[spring-orm-4.3.10.RELEASE.jar!/:4.3.10.RELEASE] 
    at org.springframework.dao.support.ChainedPersistenceExceptionTranslator.translateExceptionIfPossible(ChainedPersistenceExceptionTranslator.java:59) ~[spring-tx-4.3.10.RELEASE.jar!/:4.3.10.RELEASE] 
    at org.springframework.dao.support.DataAccessUtils.translateIfNecessary(DataAccessUtils.java:213) ~[spring-tx-4.3.10.RELEASE.jar!/:4.3.10.RELEASE] 
    at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:147) ~[spring-tx-4.3.10.RELEASE.jar!/:4.3.10.RELEASE] 
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) ~[spring-aop-4.3.10.RELEASE.jar!/:4.3.10.RELEASE] 
    at org.springframework.data.jpa.repository.support.CrudMethodMetadataPostProcessor$CrudMethodMetadataPopulatingMethodInterceptor.invoke(CrudMethodMetadataPostProcessor.java:133) ~[spring-data-jpa-1.11.6.RELEASE.jar!/:na] 
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) ~[spring-aop-4.3.10.RELEASE.jar!/:4.3.10.RELEASE] 
    at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:92) ~[spring-aop-4.3.10.RELEASE.jar!/:4.3.10.RELEASE] 
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) ~[spring-aop-4.3.10.RELEASE.jar!/:4.3.10.RELEASE] 
    at org.springframework.data.repository.core.support.SurroundingTransactionDetectorMethodInterceptor.invoke(SurroundingTransactionDetectorMethodInterceptor.java:57) ~[spring-data-commons-1.13.6.RELEASE.jar!/:na] 
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) ~[spring-aop-4.3.10.RELEASE.jar!/:4.3.10.RELEASE] 
    at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:213) ~[spring-aop-4.3.10.RELEASE.jar!/:4.3.10.RELEASE] 
    at com.sun.proxy.$Proxy90.save(Unknown Source) ~[na:na] 
    at c.g.r.i.jobs.AggService.cPh(AggService.java:150) ~[classes!/:0.0.1-SNAPSHOT] 
    at c.g.r.i.jobs.AggService.lambda$cBs$1(AggService.java:199) ~[classes!/:0.0.1-SNAPSHOT] 
    at java.util.HashMap$Values.forEach(HashMap.java:981) ~[na:1.8.0_161] 
    at c.g.r.i.jobs.AggService.cDs(AggService.java:197) ~[classes!/:0.0.1-SNAPSHOT] 
    at c.g.r.i.jobs.AggService.cPs(AggService.java:95) ~[classes!/:0.0.1-SNAPSHOT] 
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_161] 
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_161] 
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_161] 
    at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_161] 
    at org.springframework.scheduling.support.ScheduledMethodRunnable.run(ScheduledMethodRunnable.java:65) ~[spring-context-4.3.10.RELEASE.jar!/:4.3.10.RELEASE] 
    at org.springframework.scheduling.support.DelegatingErrorHandlingRunnable.run(DelegatingErrorHandlingRunnable.java:54) ~[spring-context-4.3.10.RELEASE.jar!/:4.3.10.RELEASE] 
    at org.springframework.scheduling.concurrent.ReschedulingRunnable.run(ReschedulingRunnable.java:81) [spring-context-4.3.10.RELEASE.jar!/:4.3.10.RELEASE] 
    at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511) [na:1.8.0_161] 
    at java.util.concurrent.FutureTask.run(FutureTask.java:266) [na:1.8.0_161] 
    at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$201(ScheduledThreadPoolExecutor.java:180) [na:1.8.0_161] 
    at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:293) [na:1.8.0_161] 
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) [na:1.8.0_161] 
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) [na:1.8.0_161] 
    at java.lang.Thread.run(Thread.java:748) [na:1.8.0_161] 
 Caused by: org.hibernate.PersistentObjectException: detached entity passed to persist: c.g.r.e.Resource 
    at org.hibernate.event.internal.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:124) ~[hibernate-core-5.0.12.Final.jar!/:5.0.12.Final] 
    at org.hibernate.internal.SessionImpl.firePersist(SessionImpl.java:765) ~[hibernate-core-5.0.12.Final.jar!/:5.0.12.Final] 
    at org.hibernate.internal.SessionImpl.persist(SessionImpl.java:758) ~[hibernate-core-5.0.12.Final.jar!/:5.0.12.Final] 
    at org.hibernate.jpa.event.internal.core.JpaPersistEventListener$1.cascade(JpaPersistEventListener.java:80) ~[hibernate-entitymanager-5.0.12.Final.jar!/:5.0.12.Final] 
    at org.hibernate.engine.internal.Cascade.cascadeToOne(Cascade.java:398) ~[hibernate-core-5.0.12.Final.jar!/:5.0.12.Final] 
    at org.hibernate.engine.internal.Cascade.cascadeAssociation(Cascade.java:323) ~[hibernate-core-5.0.12.Final.jar!/:5.0.12.Final] 
    at org.hibernate.engine.internal.Cascade.cascadeProperty(Cascade.java:162) ~[hibernate-core-5.0.12.Final.jar!/:5.0.12.Final] 
    at org.hibernate.engine.internal.Cascade.cascade(Cascade.java:111) ~[hibernate-core-5.0.12.Final.jar!/:5.0.12.Final] 
    at org.hibernate.event.internal.AbstractSaveEventListener.cascadeBeforeSave(AbstractSaveEventListener.java:425) ~[hibernate-core-5.0.12.Final.jar!/:5.0.12.Final] 
    at org.hibernate.event.internal.AbstractSaveEventListener.performSaveOrReplicate(AbstractSaveEventListener.java:249) ~[hibernate-core-5.0.12.Final.jar!/:5.0.12.Final] 
    at org.hibernate.event.internal.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:178) ~[hibernate-core-5.0.12.Final.jar!/:5.0.12.Final] 
    at org.hibernate.event.internal.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:121) ~[hibernate-core-5.0.12.Final.jar!/:5.0.12.Final] 
    at org.hibernate.jpa.event.internal.core.JpaPersistEventListener.saveWithGeneratedId(JpaPersistEventListener.java:67) ~[hibernate-entitymanager-5.0.12.Final.jar!/:5.0.12.Final] 
    at org.hibernate.event.internal.DefaultPersistEventListener.entityIsTransient(DefaultPersistEventListener.java:189) ~[hibernate-core-5.0.12.Final.jar!/:5.0.12.Final] 
    at org.hibernate.event.internal.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:132) ~[hibernate-core-5.0.12.Final.jar!/:5.0.12.Final] 
    at org.hibernate.event.internal.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:58) ~[hibernate-core-5.0.12.Final.jar!/:5.0.12.Final] 
    at org.hibernate.internal.SessionImpl.firePersist(SessionImpl.java:775) ~[hibernate-core-5.0.12.Final.jar!/:5.0.12.Final] 
    at org.hibernate.internal.SessionImpl.persist(SessionImpl.java:748) ~[hibernate-core-5.0.12.Final.jar!/:5.0.12.Final] 
    at org.hibernate.internal.SessionImpl.persist(SessionImpl.java:753) ~[hibernate-core-5.0.12.Final.jar!/:5.0.12.Final] 
    at org.hibernate.jpa.spi.AbstractEntityManagerImpl.persist(AbstractEntityManagerImpl.java:1146) ~[hibernate-entitymanager-5.0.12.Final.jar!/:5.0.12.Final] 
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_161] 
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_161] 
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_161] 
    at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_161] 
    at org.springframework.orm.jpa.SharedEntityManagerCreator$SharedEntityManagerInvocationHandler.invoke(SharedEntityManagerCreator.java:298) ~[spring-orm-4.3.10.RELEASE.jar!/:4.3.10.RELEASE] 
    at com.sun.proxy.$Proxy85.persist(Unknown Source) ~[na:na] 
    at org.springframework.data.jpa.repository.support.SimpleJpaRepository.save(SimpleJpaRepository.java:508) ~[spring-data-jpa-1.11.6.RELEASE.jar!/:na] 
    at org.springframework.data.jpa.repository.support.SimpleJpaRepository.save(SimpleJpaRepository.java:542) ~[spring-data-jpa-1.11.6.RELEASE.jar!/:na] 
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_161] 
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_161] 
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_161] 
    at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_161] 
    at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.executeMethodOn(RepositoryFactorySupport.java:504) ~[spring-data-commons-1.13.6.RELEASE.jar!/:na] 
    at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.doInvoke(RepositoryFactorySupport.java:489) ~[spring-data-commons-1.13.6.RELEASE.jar!/:na] 
    at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.invoke(RepositoryFactorySupport.java:461) ~[spring-data-commons-1.13.6.RELEASE.jar!/:na] 
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) ~[spring-aop-4.3.10.RELEASE.jar!/:4.3.10.RELEASE] 
    at org.springframework.data.projection.DefaultMethodInvokingMethodInterceptor.invoke(DefaultMethodInvokingMethodInterceptor.java:56) ~[spring-data-commons-1.13.6.RELEASE.jar!/:na] 
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) ~[spring-aop-4.3.10.RELEASE.jar!/:4.3.10.RELEASE] 
    at org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:99) ~[spring-tx-4.3.10.RELEASE.jar!/:4.3.10.RELEASE] 
    at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:282) ~[spring-tx-4.3.10.RELEASE.jar!/:4.3.10.RELEASE] 
    at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:96) ~[spring-tx-4.3.10.RELEASE.jar!/:4.3.10.RELEASE] 
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) ~[spring-aop-4.3.10.RELEASE.jar!/:4.3.10.RELEASE] 
    at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:136) ~[spring-tx-4.3.10.RELEASE.jar!/:4.3.10.RELEASE] 
    ... 28 common frames omitted
Ram
  • 1,743
  • 2
  • 18
  • 40
  • can you please share the code at line at 95 `c.g.r.i.jobs.AggService.cPs(AggService.java:95` – kakabali Mar 29 '18 at 10:38
  • Infact the methods - AggService.cDs(), AggService.cPs(), .AggService.cPh and .AggService.lambda() functions – kakabali Mar 29 '18 at 10:39
  • Those are just internal calls which reaches `cPh()` and the List of Agg is created in `cPh()` – Ram Mar 29 '18 at 11:16

1 Answers1

0

The answer in the post here - https://stackoverflow.com/a/13500921/2600196 can be helpful to you

It is related to the bidirectional consistency problem.

Try going through the use of CascadeType in your entity class here, you may want to use a correct type of cascading

kakabali
  • 3,824
  • 2
  • 29
  • 58
  • Thanks for your response. I read thru that before posting this question. As I said in the question, I can remove the Cascase Type or make it to CascadeType.MERGE. But then why does it runs fine if manually invoked and not when invoked via Scheduler. – Ram Mar 29 '18 at 11:14
  • the state of the entity is not getting reflected by the Hibernate/JPA in case of the scheduled run, something related to your data may be, the flow of the call might be calling it that way, it would be great if you share more code so that it can easily tracked, at least theoratically – kakabali Mar 29 '18 at 11:24
  • Ok. I will share relevant snippets shortly. But data/flow everything is same for both invocations. – Ram Mar 29 '18 at 11:49