首页 > 解决方案 > Quartz 作业抛出 InvalidDataAccessApiUsageException: no transaction is in progress;

问题描述

我有一个非常简单的石英作业,它试图从数据库中获取打印机记录,
我收到了这个错误:

org.springframework.dao.InvalidDataAccessApiUsageException: no transaction is in progress; 
nested exception is javax.persistence.TransactionRequiredException: no transaction is in progress
javax.persistence.TransactionRequiredException: no transaction is in progress

这是应用程序的代码:

@SpringBootApplication
@ComponentScan(basePackages="com.xerox.printhub") 
@EntityScan("com.xerox.printhub*")
@EnableTransactionManagement
@EnableJpaRepositories(basePackages ={"com.xerox.printhub.repository"})
@Import({ SchedulerConfig.class })
public class PrinterVerificationApp extends SpringBootServletInitializer {
    public static void main(String[] args) {
        SpringApplication.run(PrinterVerificationApp.class, args);
    }
}

这是 Quartz 作业的代码:

package com.xerox.printhub.quartz.jobs;

import javax.transaction.Transactional;
import com.google.gson.Gson;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;



public class PrinterVerificationJob implements Job{

    @Transactional
    public void execute(JobExecutionContext jobExecutionContext) {

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

    @Autowired
    Gson g;

       @Autowired
       PrinterInfoRepository printerRepo;   

        logger.debug("Trying to fetch an available printer...");

        PrinterInfo printerInfo=null;
        try {
            printerInfo = printerRepo.findOneAndLock(PrinterStatus.NEW.name());
            } catch (Exception e1) {
            logger.debug("Error!",e1);
            }

    }

Dao 对象的代码 (PrinterInfoRepository )

@Transactional
public interface PrinterInfoRepository  extends CrudRepository<PrinterInfo ,String> {

     @Lock(LockModeType.PESSIMISTIC_WRITE)//locking it to prevent other workers to access it.
     @Query("SELECT p FROM PrinterInfo p where p.statusCd = :status")
     List<PrinterInfo> findOneAndLock(@Param("status")String status);   
}

在我的应用程序中,这个 Rest 控制器与 PrinterInfoRepository 一起工作得很好

package com.xerox.printhub.controllers;

import java.text.ParseException;
import java.util.ArrayList;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/api")
public class PrinterAPIController {

    @Autowired 
    PrinterInfoRepository printerRepo;


    @PostMapping(value = "/SubmitPrinterData")
    public PrinterInfo submitPrinterData(
            @RequestBody PrinterInfoJason printerInfo) {
            //THIS METHOD IS WORKING FINE.
    }

我尝试了两个注释:

import javax.transaction.Transactional;
import org.springframework.transaction.annotation.Transactional;

我尝试使用 @service 注释 PrinterVerificationJob
我还添加了 EnableTransactionManagement

但没有任何帮助。
知道我做错了什么吗?

更新

当我不使用 LockModeType.PESSIMISTIC_WRITE 时,我在 PrinterInfoRepository-> findOneAndLock() 找到了罪魁祸首
,方法工作只是找到...当我尝试使用使用 LockModeType.PESSIMISTIC_WRITE 访问时,我得到 InvalidDataAccessApiUsageException 我做错了什么?我需要从其他工作人员那里锁定记录。

 @Lock(LockModeType.PESSIMISTIC_WRITE)//locking it to prevent other workers to access it.
 @Query("SELECT p FROM PrinterInfo p where p.statusCd = :status")
 PrinterInfo findOneAndLock(@Param("status")String status);

完整的堆栈跟踪:

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:402) 
        at org.springframework.orm.jpa.vendor.HibernateJpaDialect.translateExceptionIfPossible(HibernateJpaDialect.java:255) 
        at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.translateExceptionIfPossible(AbstractEntityManagerFactoryBean.java:527) 
        at org.springframework.dao.support.ChainedPersistenceExceptionTranslator.translateExceptionIfPossible(ChainedPersistenceExceptionTranslator.java:61) 
        at org.springframework.dao.support.DataAccessUtils.translateIfNecessary(DataAccessUtils.java:242) 
        at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:153) 
        at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) 
        at org.springframework.data.jpa.repository.support.CrudMethodMetadataPostProcessor$CrudMethodMetadataPopulatingMethodInterceptor.invoke(CrudMethodMetadataPostProcessor.java:139) 
        at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) 
        at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:93) 
        at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) 
        at org.springframework.data.repository.core.support.SurroundingTransactionDetectorMethodInterceptor.invoke(SurroundingTransactionDetectorMethodInterceptor.java:61) 
        at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) 
        at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:212) 
        at com.sun.proxy.$Proxy124.findOneAndLock(Unknown Source) 
        at com.xerox.printhub.quartz.jobs.PrinterVerificationJob.getPrinter(PrinterVerificationJob.java:158) 
        at com.xerox.printhub.quartz.jobs.PrinterVerificationJob.execute(PrinterVerificationJob.java:189) 
        at org.quartz.core.JobRunShell.run(JobRunShell.java:202) 
        at org.quartz.simpl.SimpleThrexeroxool$WorkerThread.run(SimpleThrexeroxool.java:573) 
    Caused by: javax.persistence.TransactionRequiredException: no transaction is in progress 
        at org.hibernate.query.internal.AbstractProducedQuery.doList(AbstractProducedQuery.java:1556) 
        at org.hibernate.query.internal.AbstractProducedQuery.list(AbstractProducedQuery.java:1529) 
        at org.hibernate.query.Query.getResultList(Query.java:168) 
        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$DeferredQueryInvocationHandler.invoke(SharedEntityManagerCreator.java:402) 
        at com.sun.proxy.$Proxy141.getResultList(Unknown Source) 
        at org.springframework.data.jpa.repository.query.JpaQueryExecution$CollectionExecution.doExecute(JpaQueryExecution.java:129) 
        at org.springframework.data.jpa.repository.query.JpaQueryExecution.execute(JpaQueryExecution.java:91) 
        at org.springframework.data.jpa.repository.query.AbstractJpaQuery.doExecute(AbstractJpaQuery.java:136) 
        at org.springframework.data.jpa.repository.query.AbstractJpaQuery.execute(AbstractJpaQuery.java:125) 
        at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.doInvoke(RepositoryFactorySupport.java:605) 
        at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.lambda$invoke$3(RepositoryFactorySupport.java:595) 
        at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.invoke(RepositoryFactorySupport.java:595) 
        at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) 
        at org.springframework.data.projection.DefaultMethodInvokingMethodInterceptor.invoke(DefaultMethodInvokingMethodInterceptor.java:59) 
        at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) 
        at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:294) 
        at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:98) 
        at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) 
        at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:139) 
        ... 13 more

标签: javaspringquartz-scheduler

解决方案


从您的日志中可以明显看出 - 为什么?因为如果事务处于活动状态,您将在两者之间进行代理调用,就像您在存储库上调用方法时一样。从同一日志可见。

   at com.xerox.printhub.quartz.jobs.PrinterVerificationJob.getPrinter(PrinterVerificationJob.java:158)

    at com.xerox.printhub.quartz.jobs.PrinterVerificationJob.execute(PrinterVerificationJob.java:189)

    at org.quartz.core.JobRunShell.run(JobRunShell.java:202)

您的 PrinterVerificationJob 未检测。这意味着您的 @Transactional 注释不起作用。您需要由 spring 管理您的 Bean,以便 @Transactional 注释生效。您可以做些什么来将您的执行方法的内容隔离到服务中并将其注入到 JOB 中。然后你可以用@Transctional注解这个类或者这个类的方法。该 bean 将被检测,@Transactional 注释将生效。

@Service
PrinterVerificationService {

@Transactional
public void verifyPrinter(yuor parameters here)

}

public class PrinterVerificationJob implements Job{
@Autowire
PrinterVerificationService verificationService;

public void execute(JobExecutionContext jobExecutionContext) {
    service.verifyPrinter(your prameters here)
}

如果您想按原样保留您的应用程序逻辑。您可以做的是使用已在 spring 中初始化的 @PlatformTransactionManager 并将其 @Autowire 用于您的工作。使用此事务管理器,您可以手动启动事务。有了它,您可以初始化 TransactionTemplate 并执行以下操作:

TransactionTemplate txTemplate = new TransactionTemplate(platformTransactionManagerHere);                
txTemplate.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW);
txTemplate.execute(new TransactionCallback<Object>() {
    public Object doInTransaction(TransactionStatus status) {
        // do stuff
    }
});

推荐阅读