如何避免将事务标记为仅回滚;无法提交异步任务

问题描述 投票:0回答:1

我已经开发了用于在异步任务中将文件集成到数据库中的API。我希望处理整个文件,并在数据库中记录每个错误。

我的API调用此服务

@Service
public class ImportFichier {

    @Async("taskExecutor")
    public void importReference(ImportFichierDTO importFichierDTO,
                                List<Reference> references,
                                Long idEntite,
                                Long currentUserId,
                                boolean update){
        log.debug("Request to importReference pour entite : {}", idEntite);

        for(Reference reference : references) {
            if (update) {
                referentielService.update(idEntite, reference, currentUserId, importFichierDTO.getId());
            } else {
                referentielService.add(idEntite, reference, currentUserId, importFichierDTO.getId());
            }
        }

        // mise à jour de l'heure de fin du traitement d'import
        importFichierDTO.setDateFin(ZonedDateTime.now());
        importFichierService.save(importFichierDTO);

        return;
    }

要添加数据,请致电此服务:

@Service
@Transactional
public class ReferentielCompteurServiceImpl implements ReferentielCompteurService {
 ....

@Override
@Transactional(noRollbackFor = {CustomException.class, ConstraintViolationException.class})
public Compteur add(Compteur compteur, Long entiteMereId, Long entiteId, Long userId, Long importId) {

    Optional<ArticleEtat> articleEtat = articleEtatRepository.findOneByCode(compteur.getCodeEtat());
    if (!articleEtat.isPresent()) {
        if (importId > 0) {
            importFichierTraceService.add(importId, compteur.getUuidReference().toString(), CustomError.ERROR_ARTICLE_ETAT_NOT_FOUND.getErrorDescription());
            return compteur;
        } else {
            throw new CustomException(CustomError.ERROR_ARTICLE_ETAT_NOT_FOUND);
        }
    }

    ....
    ReferentielCompteurDTO result = save(referentielCompteurDTO, importId);

并且方法“保存”在同一服务中:

@Override
@Transactional(noRollbackFor = {CustomException.class, ConstraintViolationException.class})
public ReferentielCompteurDTO save(ReferentielCompteurDTO referentielCompteurDTO, Long importId) {
    log.debug("Request to save ReferentielCompteur : {}", referentielCompteurDTO);

    if (referentielCompteurDTO.getDateCreation() == null) {
        referentielCompteurDTO.setDateCreation(ZonedDateTime.now());
    }
    referentielCompteurDTO.setDateModification(ZonedDateTime.now());

    ReferentielCompteur referentielCompteur = referentielCompteurMapper.toEntity(referentielCompteurDTO);

    try {
        referentielCompteur = referentielCompteurRepository.save(referentielCompteur);
    } catch (ConstraintViolationException cve) {
        importFichierTraceService.add(importId, referentielCompteurDTO.getReferenceId().toString(), cve.getMessage());
    }

    return referentielCompteurMapper.toDto(referentielCompteur);
}

[当我生成ConstraintViolationException时,我有此异常:

 Transaction was marked for rollback only; cannot commit' and exception = 'Transaction was marked for rollback only; cannot commit; nested exception is org.hibernate.TransactionException: Transaction was marked for rollback only; cannot commit'

org.springframework.orm.jpa.JpaSystemException: Transaction was marked for rollback only; cannot commit; nested exception is org.hibernate.TransactionException: Transaction was marked for rollback only; cannot commit
    at org.springframework.orm.jpa.vendor.HibernateJpaDialect.convertHibernateAccessException(HibernateJpaDialect.java:312)
    at org.springframework.orm.jpa.vendor.HibernateJpaDialect.translateExceptionIfPossible(HibernateJpaDialect.java:223)
    at org.springframework.orm.jpa.JpaTransactionManager.doCommit(JpaTransactionManager.java:540)
    at org.springframework.transaction.support.AbstractPlatformTransactionManager.processCommit(AbstractPlatformTransactionManager.java:746)
    at org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:714)
    at org.springframework.transaction.interceptor.TransactionAspectSupport.commitTransactionAfterReturning(TransactionAspectSupport.java:532)
    at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:304)
    at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:98)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:185)
    at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:92)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:185)
    at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:688)

我看过几篇文章,但是我不明白如何解决这个问题,并且有可能

您能帮我吗?

java spring jpa rollback
1个回答
0
投票

按照Deinum先生的建议,我尝试:

for importFichierTraceService.add

@Transactional(propagation = REQUIRES_NEW)
public void add(Long importId, String line, String message) {

我删除@Transactional并捕获异常

@Override
public ReferentielCompteurDTO save(ReferentielCompteurDTO referentielCompteurDTO, Long importId) {

并在以下位置添加catch异常:

@Override
public Compteur add(Compteur compteur, Long entiteMereId, Long entiteId, Long userId, Long importId) { 

try {
        result = save(referentielCompteurDTO, importId);
    } catch (ConstraintViolationException cve) {
        importFichierTraceService.add(importId, referentielCompteurDTO.getReferenceId().toString(), cve.getMessage());
        return compteur;
    }

结果相同

© www.soinside.com 2019 - 2024. All rights reserved.