Quartz作业抛出InvalidDataAccessApiUsageException:没有事务正在进行;

use*_*026 6 java spring quartz-scheduler

我有一个非常简单的石英作业,试图从数据库中获取打印机记录,但出现
此错误:

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
Run Code Online (Sandbox Code Playgroud)

这是应用程序的代码:

@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);
    }
}
Run Code Online (Sandbox Code Playgroud)

这是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);
            }

    }
Run Code Online (Sandbox Code Playgroud)

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);   
}
Run Code Online (Sandbox Code Playgroud)

在我的应用程序中,此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.
    }
Run Code Online (Sandbox Code Playgroud)

我尝试了两个注释:

import javax.transaction.Transactional;
import org.springframework.transaction.annotation.Transactional;
Run Code Online (Sandbox Code Playgroud)

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

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

更新


当我不使用LockModeType.PESSIMISTIC_WRITE时,我在PrinterInfoRepository-> findOneAndLock()中找到了罪魁祸首,方法只能找到...当我尝试使用use 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);
Run Code Online (Sandbox Code Playgroud)

全栈跟踪:

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
Run Code Online (Sandbox Code Playgroud)

Ale*_*rov 4

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

   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)
Run Code Online (Sandbox Code Playgroud)

您的 PrinterVerificationJob 未检测。这意味着您的 @Transactional 注释不起作用。您需要您的 Bean 由 spring 管理,@Transactional 注解才能生效。您可以做什么来将执行方法的内容隔离到服务中并将其注入到作业中。然后你可以用@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)
}
Run Code Online (Sandbox Code Playgroud)

如果您想按原样保留应用程序逻辑。您可以做的是使用已在 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
    }
});
Run Code Online (Sandbox Code Playgroud)