【问题标题】:Exception in Spring asynchronous job - InvalidDataAccessApiUsageException: no transaction is in progressSpring 异步作业中的异常 - InvalidDataAccessApiUsageException:没有正在进行的事务
【发布时间】:2018-09-07 22:27:39
【问题描述】:

场景是,我有一个带有 Spring Batch 作业的 Spring Boot 应用程序。我正在尝试使用@EnableAsyncThreadPoolTaskExecutor 使批处理作业异步,然后将此taskExecutor 分配给JobLauncher。在此更改之后,作业异步运行,但我在持久化或更新数据库时遇到问题:

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.AbstractEntityManagerFactoryBean.translateExceptionIfPossible(AbstractEntityManagerFactoryBean.java:489)
    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.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:99)
    at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:282)
    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.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:673)
    at com.abc.fin.rec.batch.dao.impl.CustomerDaoImpl$$EnhancerBySpringCGLIB$$b55f85f1.updateRequestSummary(<generated>)
    at com.abc.fin.rec.batch.service.impl.BatchServiceImpl.updateRequestSummary(BatchServiceImpl.java:122)
    at com.abc.fin.rec.batch.service.impl.BatchServiceImpl$$FastClassBySpringCGLIB$$b4c3b9f7.invoke(<generated>)
    at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204)
    at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:738)
    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:282)
    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.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:673)
    at com.abc.fin.rec.batch.service.impl.BatchServiceImpl$$EnhancerBySpringCGLIB$$b9160b39.updateRequestSummary(<generated>)
    at com.abc.fin.rec.batch.cust.match.req.WriteToFileJobExecutionListener.beforeJob(WriteToFileJobExecutionListener.java:97)
    at org.springframework.batch.core.listener.CompositeJobExecutionListener.beforeJob(CompositeJobExecutionListener.java:73)
    at org.springframework.batch.core.job.AbstractJob.execute(AbstractJob.java:303)
    at org.springframework.batch.core.launch.support.SimpleJobLauncher$1.run(SimpleJobLauncher.java:135)
    at org.springframework.cloud.sleuth.instrument.async.SpanContinuingTraceRunnable.run(SpanContinuingTraceRunnable.java:52)
    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.internal.SessionImpl.checkTransactionNeeded(SessionImpl.java:3430)
        at org.hibernate.internal.SessionImpl.doFlush(SessionImpl.java:1397)
        at org.hibernate.internal.SessionImpl.flush(SessionImpl.java:1393)
        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.$Proxy133.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.$Proxy127.flush(Unknown Source)
        at com.abc.fin.rec.batch.dao.impl.CustomerDaoImpl.updateRequestSummary(CustomerDaoImpl.java:138)
        at com.abc.fin.rec.batch.dao.impl.CustomerDaoImpl$$FastClassBySpringCGLIB$$333ee7df.invoke(<generated>)
        at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204)
        at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:738)
        at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157)
        at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:136)
        ... 26 common frames omitted

感谢您的帮助!

【问题讨论】:

标签: hibernate spring-boot jpa asynchronous spring-batch


【解决方案1】:

我已经在其他情况下遇到过这种问题,只有一种有效的方法可以找出根源: 在 org.hibernate.internal.SessionImpl.checkTransactionNeeded 中放置断点 并在 org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction 然后尝试了解为什么稍后创建的事务(应该是)不被第一个识别。

【讨论】:

  • 我试图调试这些框架类,但我什么也做不了。你能提供更多细节吗?你的解决方法是什么?由于某种原因,我无法打开 SessionImpl 源来放置断点。
  • 如果你不能放置断点,在某些情况下我需要调试这种“tx 问题”并且没有一个完全是你的,在 JUNIT 中有一个@Transactional隐藏在用于配置测试的复合注释中(当它不应该存在时,tx 已经存在......),另一个是 @Transactional 方法的“自我”调用(也在 @Async 上下文中),因此没有跨越代理边界 -> 没有应用 Aspect,但这不是你的情况,因为我们在堆栈跟踪中看到 TransactionInterceptor,另一种情况是调试 REQUIRES_NEW 在 JUNIT 中不起作用
【解决方案2】:

JobExecution#beforeJob 不在 Spring Batch 管理的事务范围内执行。您可能希望将 @Transactional 添加到您的 WriteToFileJobExecutionListener#beforeJob 方法中。

【讨论】:

  • 我也试过了,但它会导致同样的错误。我在 beforeJob 方法和 Dao 类级别上有 @Transactional 注释。
【解决方案3】:

@Transactional(propagation = Propagation.REQUIRES_NEW)注解处理数据库访问逻辑的作业方法。

【讨论】:

  • 它似乎不起作用。以下是我按照建议执行的操作,如果遗漏任何内容,请纠正我:@Bean @Transactional(propagation = Propagation.REQUIRES_NEW) public Job collectCustRequestData() throws Exception { final JobBuilder jb = jobBuilderFactory.get("gatherCustRequestData"); jb.listener(gatherDataJobExecutionListener()); SimpleJobBuilder sjb = jb.start(step1()); sjb = sjb.next(step2());返回 sjb.build(); }
  • 这个方法好像没有做任何db写操作
  • 其实db写操作是通过DAO在gatherDataJobExecutionListener中进行的。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-08-16
  • 1970-01-01
  • 2016-05-20
  • 2015-05-11
  • 2016-03-26
  • 2013-12-09
  • 2017-12-30
相关资源
最近更新 更多