Возникновение кварцевого задания InvalidDataAccessApiUsageException: транзакция не выполняется; - PullRequest
6 голосов
/ 30 апреля 2019

У меня очень простая кварцевая работа, которая пытается извлечь запись принтера из БД,
Я получаю эту ошибку:

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;

И я попытался аннотировать JobVerificationJob с помощью @ service
Я также добавил EnableTransactionManagement

Ноничего не помогает.
Есть идеи, что я делаю неправильно?

ОБНОВЛЕНИЕ

Я нашел виновника в PrinterInfoRepository-> findOneAndLock ()
, когда яне используйте LockModeType.PESSIMISTIC_WRITE, метод работает, просто найдите ... когда я пытаюсь получить доступ с помощью использования 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

1 Ответ

3 голосов
/ 14 июня 2019

Из твоего лога очевидно - почему? Потому что, если бы транзакция была активной, у вас был бы вызов Proxy между тем, как вы вызываете метод в хранилище. Видно из того же журнала.

   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 не работает. Весной вам нужно управлять своим Bean-компонентом, чтобы аннотация @Transactional вступила в силу. Что вы можете сделать, чтобы изолировать содержимое вашего метода execute в сервис и внедрить его в JOB. Затем вы можете аннотировать этот класс или метод этого класса с помощью @Transctional. Этот бин получит инструментарий, и аннотация @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)
}

Если вы хотите сохранить логику приложения как есть. Что вы можете сделать, это использовать @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
    }
});
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...