【问题标题】:Spring Data JPA - javax.persistence.TransactionRequiredException: Executing an update/delete querySpring Data JPA - javax.persistence.TransactionRequiredException:执行更新/删除查询
【发布时间】:2020-06-08 00:00:10
【问题描述】:

我正在尝试使用 Spring CRUDRepository 类更新表(@query 注释)。 但是系统在更新时抛出错误。我用谷歌搜索并发现许多线程通知添加事务注释。我做了,但没有效果。有人可以帮我解决这个问题吗?

import java.util.ArrayList;
import java.util.List;

import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.CrudRepository;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import org.springframework.transaction.annotation.Transactional;

    @Repository
    public interface PrintJobItemRepo extends CrudRepository<PrintJobItem, Integer> {

        @Modifying     
        @Query(value =  PrintBatchConstants.UPDATE_SEQUENCE_NUMBER_QUERY)
        public void updateSequenceNumberInPrintItemTable(String sequenceNumber, String groupId);    
    }

    public class PrintBatchConstants {

        public static final String UPDATE_SEQUENCE_NUMBER_QUERY="UPDATE PRINT_JOB_ITEM SET PRINT_STATUS=null,SEQUENCE_NBR=(?1) "
                                                                 + "where GROUP_ID=(?2) and sequence_nbr is null";

    }

以下错误

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:403) ~[spring-orm-5.2.5.RELEASE.jar:5.2.5.RELEASE]
    at org.springframework.orm.jpa.vendor.HibernateJpaDialect.translateExceptionIfPossible(HibernateJpaDialect.java:257) ~[spring-orm-5.2.5.RELEASE.jar:5.2.5.RELEASE]
    at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.translateExceptionIfPossible(AbstractEntityManagerFactoryBean.java:528) ~[spring-orm-5.2.5.RELEASE.jar:5.2.5.RELEASE]
    at org.springframework.dao.support.ChainedPersistenceExceptionTranslator.translateExceptionIfPossible(ChainedPersistenceExceptionTranslator.java:61) ~[spring-tx-5.2.5.RELEASE.jar:5.2.5.RELEASE]
    at org.springframework.dao.support.DataAccessUtils.translateIfNecessary(DataAccessUtils.java:242) ~[spring-tx-5.2.5.RELEASE.jar:5.2.5.RELEASE]
    at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:153) ~[spring-tx-5.2.5.RELEASE.jar:5.2.5.RELEASE]
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.2.5.RELEASE.jar:5.2.5.RELEASE]
    at org.springframework.data.jpa.repository.support.CrudMethodMetadataPostProcessor$CrudMethodMetadataPopulatingMethodInterceptor.invoke(CrudMethodMetadataPostProcessor.java:149) ~[spring-data-jpa-2.2.6.RELEASE.jar:2.2.6.RELEASE]
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.2.5.RELEASE.jar:5.2.5.RELEASE]
    at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:95) ~[spring-aop-5.2.5.RELEASE.jar:5.2.5.RELEASE]
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.2.5.RELEASE.jar:5.2.5.RELEASE]
    at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:212) ~[spring-aop-5.2.5.RELEASE.jar:5.2.5.RELEASE]
    at com.sun.proxy.$Proxy83.updateSequenceNumberInPrintItemTable(Unknown Source) ~[na:na]
    at com.acm.bap.printbatch.tasklet.UpdateSequenceNumbers.updateSequenceNumbers(UpdateSequenceNumbers.java:100) ~[classes/:na]
    at com.acm.bap.printbatch.tasklet.UpdateSequenceNumbers.execute(UpdateSequenceNumbers.java:56) ~[classes/:na]
    at com.acm.bap.printbatch.tasklet.UpdateSequenceNumbers$$FastClassBySpringCGLIB$$afc7f92b.invoke(<generated>) ~[classes/:na]
    at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218) ~[spring-core-5.2.5.RELEASE.jar:5.2.5.RELEASE]
    at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:687) ~[spring-aop-5.2.5.RELEASE.jar:5.2.5.RELEASE]
    at com.acm.bap.printbatch.tasklet.UpdateSequenceNumbers$$EnhancerBySpringCGLIB$$88a0f8bb.execute(<generated>) ~[classes/:na]
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_162]
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_162]
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_162]
    at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_162]
    at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:344) ~[spring-aop-5.2.5.RELEASE.jar:5.2.5.RELEASE]
    at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:198) ~[spring-aop-5.2.5.RELEASE.jar:5.2.5.RELEASE]
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163) ~[spring-aop-5.2.5.RELEASE.jar:5.2.5.RELEASE]
    at org.springframework.aop.support.DelegatingIntroductionInterceptor.doProceed(DelegatingIntroductionInterceptor.java:136) ~[spring-aop-5.2.5.RELEASE.jar:5.2.5.RELEASE]
    at org.springframework.aop.support.DelegatingIntroductionInterceptor.invoke(DelegatingIntroductionInterceptor.java:124) ~[spring-aop-5.2.5.RELEASE.jar:5.2.5.RELEASE]
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.2.5.RELEASE.jar:5.2.5.RELEASE]
    at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:212) ~[spring-aop-5.2.5.RELEASE.jar:5.2.5.RELEASE]
    at com.sun.proxy.$Proxy67.execute(Unknown Source) ~[na:na]
    at org.springframework.batch.core.step.tasklet.TaskletStep$ChunkTransactionCallback.doInTransaction(TaskletStep.java:407) ~[spring-batch-core-4.2.1.RELEASE.jar:4.2.1.RELEASE]
    at org.springframework.batch.core.step.tasklet.TaskletStep$ChunkTransactionCallback.doInTransaction(TaskletStep.java:331) ~[spring-batch-core-4.2.1.RELEASE.jar:4.2.1.RELEASE]
    at org.springframework.transaction.support.TransactionTemplate.execute(TransactionTemplate.java:140) ~[spring-tx-5.2.5.RELEASE.jar:5.2.5.RELEASE]
    at org.springframework.batch.core.step.tasklet.TaskletStep$2.doInChunkContext(TaskletStep.java:273) ~[spring-batch-core-4.2.1.RELEASE.jar:4.2.1.RELEASE]
    at org.springframework.batch.core.scope.context.StepContextRepeatCallback.doInIteration(StepContextRepeatCallback.java:82) ~[spring-batch-core-4.2.1.RELEASE.jar:4.2.1.RELEASE]
    at org.springframework.batch.repeat.support.RepeatTemplate.getNextResult(RepeatTemplate.java:375) ~[spring-batch-infrastructure-4.2.1.RELEASE.jar:4.2.1.RELEASE]
    at org.springframework.batch.repeat.support.RepeatTemplate.executeInternal(RepeatTemplate.java:215) ~[spring-batch-infrastructure-4.2.1.RELEASE.jar:4.2.1.RELEASE]
    at org.springframework.batch.repeat.support.RepeatTemplate.iterate(RepeatTemplate.java:145) ~[spring-batch-infrastructure-4.2.1.RELEASE.jar:4.2.1.RELEASE]
    at org.springframework.batch.core.step.tasklet.TaskletStep.doExecute(TaskletStep.java:258) ~[spring-batch-core-4.2.1.RELEASE.jar:4.2.1.RELEASE]
    at org.springframework.batch.core.step.AbstractStep.execute(AbstractStep.java:208) ~[spring-batch-core-4.2.1.RELEASE.jar:4.2.1.RELEASE]
    at org.springframework.batch.core.job.SimpleStepHandler.handleStep(SimpleStepHandler.java:148) [spring-batch-core-4.2.1.RELEASE.jar:4.2.1.RELEASE]
    at org.springframework.batch.core.job.flow.JobFlowExecutor.executeStep(JobFlowExecutor.java:68) [spring-batch-core-4.2.1.RELEASE.jar:4.2.1.RELEASE]
    at org.springframework.batch.core.job.flow.support.state.StepState.handle(StepState.java:68) [spring-batch-core-4.2.1.RELEASE.jar:4.2.1.RELEASE]
    at org.springframework.batch.core.job.flow.support.SimpleFlow.resume(SimpleFlow.java:169) [spring-batch-core-4.2.1.RELEASE.jar:4.2.1.RELEASE]
    at org.springframework.batch.core.job.flow.support.SimpleFlow.start(SimpleFlow.java:144) [spring-batch-core-4.2.1.RELEASE.jar:4.2.1.RELEASE]
    at org.springframework.batch.core.job.flow.FlowJob.doExecute(FlowJob.java:137) [spring-batch-core-4.2.1.RELEASE.jar:4.2.1.RELEASE]
    at org.springframework.batch.core.job.AbstractJob.execute(AbstractJob.java:319) [spring-batch-core-4.2.1.RELEASE.jar:4.2.1.RELEASE]
    at org.springframework.batch.core.launch.support.SimpleJobLauncher$1.run(SimpleJobLauncher.java:147) [spring-batch-core-4.2.1.RELEASE.jar:4.2.1.RELEASE]
    at org.springframework.core.task.SyncTaskExecutor.execute(SyncTaskExecutor.java:50) [spring-core-5.2.5.RELEASE.jar:5.2.5.RELEASE]
    at org.springframework.batch.core.launch.support.SimpleJobLauncher.run(SimpleJobLauncher.java:140) [spring-batch-core-4.2.1.RELEASE.jar:4.2.1.RELEASE]
    at com.acm.bap.printbatch.AgencyBillPayFileUploadApplication.run(AgencyBillPayFileUploadApplication.java:51) [classes/:na]
    at org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:784) [spring-boot-2.2.6.RELEASE.jar:2.2.6.RELEASE]
    at org.springframework.boot.SpringApplication.callRunners(SpringApplication.java:768) [spring-boot-2.2.6.RELEASE.jar:2.2.6.RELEASE]
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:322) [spring-boot-2.2.6.RELEASE.jar:2.2.6.RELEASE]
    at com.acm.bap.printbatch.AgencyBillPayFileUploadApplication.main(AgencyBillPayFileUploadApplication.java:39) [classes/:na]
Caused by: javax.persistence.TransactionRequiredException: Executing an update/delete query
    at org.hibernate.internal.AbstractSharedSessionContract.checkTransactionNeededForUpdateOperation(AbstractSharedSessionContract.java:413) ~[hibernate-core-5.4.12.Final.jar:5.4.12.Final]
    at org.hibernate.query.internal.AbstractProducedQuery.executeUpdate(AbstractProducedQuery.java:1605) ~[hibernate-core-5.4.12.Final.jar:5.4.12.Final]
    at org.springframework.data.jpa.repository.query.JpaQueryExecution$ModifyingExecution.doExecute(JpaQueryExecution.java:238) ~[spring-data-jpa-2.2.6.RELEASE.jar:2.2.6.RELEASE]
    at org.springframework.data.jpa.repository.query.JpaQueryExecution.execute(JpaQueryExecution.java:88) ~[spring-data-jpa-2.2.6.RELEASE.jar:2.2.6.RELEASE]
    at org.springframework.data.jpa.repository.query.AbstractJpaQuery.doExecute(AbstractJpaQuery.java:154) ~[spring-data-jpa-2.2.6.RELEASE.jar:2.2.6.RELEASE]
    at org.springframework.data.jpa.repository.query.AbstractJpaQuery.execute(AbstractJpaQuery.java:142) ~[spring-data-jpa-2.2.6.RELEASE.jar:2.2.6.RELEASE]
    at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.doInvoke(RepositoryFactorySupport.java:618) ~[spring-data-commons-2.2.6.RELEASE.jar:2.2.6.RELEASE]
    at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.invoke(RepositoryFactorySupport.java:605) ~[spring-data-commons-2.2.6.RELEASE.jar:2.2.6.RELEASE]
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.2.5.RELEASE.jar:5.2.5.RELEASE]
    at org.springframework.data.projection.DefaultMethodInvokingMethodInterceptor.invoke(DefaultMethodInvokingMethodInterceptor.java:80) ~[spring-data-commons-2.2.6.RELEASE.jar:2.2.6.RELEASE]
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.2.5.RELEASE.jar:5.2.5.RELEASE]
    at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:366) ~[spring-tx-5.2.5.RELEASE.jar:5.2.5.RELEASE]
    at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:118) ~[spring-tx-5.2.5.RELEASE.jar:5.2.5.RELEASE]
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.2.5.RELEASE.jar:5.2.5.RELEASE]
    at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:139) ~[spring-tx-5.2.5.RELEASE.jar:5.2.5.RELEASE]
    ... 50 common frames omitted

我已根据 cmets 更新了消费类

    public class UpdateSequenceNumbers extends PrintBatchConstants implements Tasklet { 

        static final Logger logger = LoggerFactory.getLogger(UpdateSequenceNumbers.class);

        @Autowired
        PrintJobItemRepo pjr;

        @Override
        public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws Exception {

            ArrayList<String> grpIds=(ArrayList)chunkContext.getStepContext().getJobExecutionContext().get(PrintBatchConstants.batchGroupIds);

            String groupIds = BatchCommonUtilities.getStringFromList((List<String>) chunkContext.getStepContext().getJobExecutionContext().get(PrintBatchConstants.batchGroupIds));

            List<String> flatRecords = pjr.findFlatGroupIdsIn(grpIds);
            List<String> foldRecords = pjr.findFoldGroupIdsIn(grpIds);

            logger.info("Flat SIZE "+flatRecords.size());
            logger.info("Fold SIZE "+ foldRecords.size());

           this.updateSequenceNumbers(flatRecords);
            this.updateSequenceNumbers(foldRecords);

            return null;
        }
        @Transactional
        public void updateSequenceNumbers(List<String> groupIds) {

            logger.info("Enter -> updateSequenceNumber");

            int groupNosSize=groupIds.size();

            StringBuilder sequenceNbr=null;

            for (int i = 0; i < groupIds.size(); i++) {
                    sequenceNbr=new StringBuilder();
                    sequenceNbr.append(i+1);
                    sequenceNbr.append(" Of ");
                    sequenceNbr.append(groupNosSize);
                    pjr.updateSequenceNumberInPrintItemTable(sequenceNbr.toString(),groupIds.get(i));
            }
            logger.info("Completed -> updateSequenceNumber");
        }

入口点类

@SpringBootApplication
@ComponentScan(basePackages = "com.acm.bap.printbatch")
@EnableTransactionManagement
@ImportResource({ "BAPBatchInfrastructure.xml", "DownstreamAppConfig.xml" })
public class DownstreamFileUploadApplication extends PrintBatchConstants implements CommandLineRunner {

    @Autowired
    private NotifyConfig notify;

    @Autowired
    private ApplicationContext ctx;

    static final Logger logger = LoggerFactory.getLogger(DownstreamFileUploadApplication.class);

    public static void main(String[] args) {
        SpringApplication application = new SpringApplication(DownstreamFileUploadApplication.class);

        application.setBannerMode(Banner.Mode.OFF);
        application.run(args);

    }

    @Override
    public void run(String... args) throws Exception {

        logger.info(notify.getEnvironment());

        JobLauncher jobLauncher = ctx.getBean(JobLauncher.class);
        Job job = ctx.getBean(Job.class);

        jobLauncher.run(job,
                new JobParametersBuilder()
                .addString(batchDocumentClass, "InvoiceStatementDocumentation")
                .addString(batchType, "2020-01-27")
                .addString(batchEmailID, notify.getSupportEmailId())
                .addString(batchEnvironment, notify.getEnvironment())
                .toJobParameters());



    }

}

【问题讨论】:

  • 我认为你需要类上的注释'EndUserTransaction'。有变体,或者,请参阅文档
  • 嗨,Adrian,我在文档中找不到任何此类注释。我想我已经添加了必需的注释,但这里缺少其他东西。
  • 您对注释的看法是正确的,对不起。这是一个自定义注释...哎呀。
  • 可以分享一下消费类吗?
  • 嗨阿德里安,我已经添加了消费类。请检查

标签: java spring spring-boot spring-data-jpa spring-data


【解决方案1】:

在 PrintJobItemRepo 尝试@Transactional,而不是在方法级别应用它

    @Repository
    @Transactional
    public interface PrintJobItemRepo extends CrudRepository<PrintJobItem, Integer> 

【讨论】:

    【解决方案2】:

    @Transactional 注释作为 Spring 方面工作,这意味着 Spring 使用注释方法(和代理方法)创建类的代理,因此在运行时对该方法的调用将被定向到代理方法,这将对真实方法的调用包装在事务中。

    在您的代码中,从存储库中删除 @Transactional:

    public interface PrintJobItemRepo extends CrudRepository<PrintJobItem, Integer> {
    
        @Modifying     
        @Query(value =  PrintBatchConstants.UPDATE_SEQUENCE_NUMBER_QUERY)
        public void updateSequenceNumberInPrintItemTable(String sequenceNumber, String groupId);
    }
    

    我也删除了@EnableTransactionManagement,把它放在一个带有@Configuration注解的bean中,或者和@SpringBootApplication放在同一个类中。

    接下来,将@Transactional 放入进行更新调用的方法中:

    @Transactional
    public void updateSequenceNumbers(List<String> groupIds) {
    
        logger.info("Enter -> updateSequenceNumber");
    
        int groupNosSize=groupIds.size();
    
        StringBuilder sequenceNbr=null;
    
        for (int i = 0; i < groupIds.size(); i++) {
                sequenceNbr=new StringBuilder();
                sequenceNbr.append(i+1);
                sequenceNbr.append(" Of ");
                sequenceNbr.append(groupNosSize);
    
    
                pjr.updateSequenceNumberInPrintItemTable(sequenceNbr.toString(),groupIds.get(i));
        }
    
        logger.info("Completed -> updateSequenceNumber");
    
    }
    

    让我知道它是否有效。

    【讨论】:

    • 嗨卡洛斯哈维尔,感谢您的解释。我已经用你的建议更新了我的原始帖子。我试过了,但它仍然抛出同样的错误,没有区别。请指教。
    • 能否请您提供整个异常堆栈跟踪。
    • 嗨 Carlos Javier,我添加了完整的异常堆栈跟踪。请检查。
    • 你把@EnableTransactionManagement注解放在哪里了?
    • 嗨 CarlosJavier,我在我的 jar 的入口点 Class 中添加了 @EnableTransactionManagement,springboot 应用程序在此初始化。
    【解决方案3】:

    在我的情况下.... 将方法 @Transactional 放入 Spring 的上下文而不是外部

    【讨论】:

      【解决方案4】:

      @abhinav kumar 的答案对我有用,你只需要在你的界面中放上@Transactional 注释

      @Repository
      @Transactional
      public interface PrintJobItemRepo extends CrudRepository<PrintJobItem, Integer> 
      

      【讨论】:

      • 哪个@Transactional? javax.transaction 还是 org.springframework.transaction.annotation?
      猜你喜欢
      • 2013-04-18
      • 1970-01-01
      • 2023-03-26
      • 2014-07-25
      • 1970-01-01
      • 2014-09-23
      • 2021-02-12
      • 1970-01-01
      • 2021-10-10
      相关资源
      最近更新 更多