事务性不会在使用Data JPA的Spring Boot中回退已检查的异常

如何解决事务性不会在使用Data JPA的Spring Boot中回退已检查的异常

我有一个ProcessRecon用例类,有一个名为execute方法。它使用Reconciliation保存实体paymentRepository.saveRecon,并使用paymentRepository.sendReconAck调用Web服务作为确认的一部分。

现在,这种外部Web服务可能会失败,在这种情况下,我想回滚更改,即保存的实体。由于我使用的是Unirest,因此会抛出UnirestException,这是一个已检查的异常。

控制台上没有错误,但这可能会有所帮助。 [更新]

2020-08-20 17:21:42,035 DEBUG [http-nio-7012-exec-6] org.springframework.transaction.support.AbstractPlatformTransactionManager: Creating new transaction with name [com.eyantra.payment.features.payment.domain.usecases.ProcessRecon.execute]:PROPAGATION_required,ISOLATION_DEFAULT,-com.mashape.unirest.http.exceptions.UnirestException
...
2020-08-20 17:21:44,041 DEBUG [http-nio-7012-exec-2] org.springframework.transaction.support.AbstractPlatformTransactionManager: Initiating transaction rollback
2020-08-20 17:21:44,044 DEBUG [http-nio-7012-exec-2] org.springframework.orm.jpa.JpaTransactionManager: Rolling back JPA transaction on EntityManager [SessionImpl(621663440<open>)]
2020-08-20 17:21:44,059 DEBUG [http-nio-7012-exec-2] org.springframework.orm.jpa.JpaTransactionManager: Not closing pre-bound JPA EntityManager after transaction
2020-08-20 17:22:40,020 DEBUG [http-nio-7012-exec-2] org.springframework.orm.jpa.support.OpenEntityManagerInViewInterceptor: Closing JPA EntityManager in OpenEntityManagerInViewInterceptor

此刻我看到的是即使存在UnirestException,实体也被推送到数据库。但我希望没有数据保存到数据库

我正在将Spring Boot 2.3.3与MysqL 5.7一起使用。这是我的代码

ProcessRecon.java

@Usecase // this custom annotation is derived from @service
public class ProcessRecon {

    private final PaymentRepository paymentRepository;

    @Autowired
    public ProcessRecon(PaymentRepository paymentRepository) {
        this.paymentRepository = paymentRepository;
    }

    @Transactional(rollbackFor = UnirestException.class)
    public Reconciliation execute(final Reconciliation reconciliation) throws UnirestException {
        
        PaymentDetails paymentDetails = paymentRepository.getByReqId(reconciliation.getReqId());

        if (paymentDetails == null)
            throw new EntityNotFoundException(ExceptionMessages.PAYMENT_DETAILS_NOT_FOUND);
        reconciliation.setPaymentDetails(paymentDetails);

        Long transId = null;
        if (paymentDetails.getImmediateResponse() != null)
            transId = paymentDetails.getImmediateResponse().getTransId();

        if (transId != null)
            reconciliation.setTransId(transId);

        if (reconciliation.getTransId() == null)
            throw new ValidationException("transId should be provided in Reconciliation if there is no immediate" +
                    " response for a particular reqId!");

        // THIS GETS SAVED
        Reconciliation savedRecon = paymentRepository.saveRecon(reconciliation);
        paymentDetails.setReconciliation(savedRecon);
        
        // IF THROWS SOME ERROR,ROLLBACK
        paymentRepository.sendReconAck(reconciliation);
        return savedRecon;
    }
}

PaymentRepositoryImpl.java

@CleanRepository
public class PaymentRepositoryImpl implements PaymentRepository {

    @Override
    public String sendReconAck(final Reconciliation recon) throws UnirestException {
        // AckNowledge OP
        return sendAck(recon.getRequestType(),recon.getTransId());
    }

    String sendAck(final String requestType,final Long transId) throws UnirestException {
        // Todo: Check if restTemplate can work with characters (requestType)
        final Map<String,Object> queryParams = new HashMap<String,Object>();
        queryParams.put("transId",transId);
        queryParams.put("requestType",requestType);

        logger.debug("{}",queryParams);

        final HttpResponse<String> result = Unirest.get(makeAckUrl()).queryString(queryParams).asstring();

        logger.debug("Output of ack with queryParams {} is {}",queryParams,result.getBody());
        return result.getBody();
    }

    @Override
    public Reconciliation saveRecon(final Reconciliation recon) {
        try {
            return reconDS.save(recon);
        }
        catch (DataIntegrityViolationException ex) {
            throw new EntityExistsException(ExceptionMessages.CONSTRAINT_VIOLATION);
        }
    }
}

ReconciliationDatasource.java

@Datasource // extends from @Repository
public interface ReconciliationDatasource extends JpaRepository<Reconciliation,Long> {
    List<Reconciliation> findByPaymentDetails_User_Id(Long userId);
}

解决方法

要使注释生效,您必须使用接口而不是使用类进行依赖项注入。

interface ProcessRecon {
      Reconciliation execute(final Reconciliation reconciliation) 
          throws UnirestException;
}

然后

@Usecase
public class ProcessReconImpl implements ProcessRecon {

    private final PaymentRepository paymentRepository;

    @Autowired
    public ProcessReconImpl(PaymentRepository paymentRepository) {
        this.paymentRepository = paymentRepository;
    }

    @Transactional(rollbackFor = UnirestException.class)
    public Reconciliation execute(final Reconciliation reconciliation) throws UnirestException {
        //method implementation...
    }
}

用法

@Autowired
ProcessRecon processRecon;

public void executeServiceMethod(Reconciliation reconciliation) {
    processRecon.execute(reconciliation)
}

通过这种方式,您可以获得ProcessReconImpl的代理,并通过注释提供了其他功能。

,

我假设这些表的默认引擎为 InnoDB ,但是我想知道,这些表是使用 MyISAM 引擎创建的,该引擎不支持事务。

我通过使用下面的属性here

解决了该问题
spring.jpa.database-platform=org.hibernate.dialect.MySQL5InnoDBDialect

代替

spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL5Dialect

这是唯一需要的更改。谢谢!

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其他元素将获得点击?
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。)
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbcDriver发生异常。为什么?
这是用Java进行XML解析的最佳库。
Java的PriorityQueue的内置迭代器不会以任何特定顺序遍历数据结构。为什么?
如何在Java中聆听按键时移动图像。
Java“Program to an interface”。这是什么意思?
Java在半透明框架/面板/组件上重新绘画。
Java“ Class.forName()”和“ Class.forName()。newInstance()”之间有什么区别?
在此环境中不提供编译器。也许是在JRE而不是JDK上运行?
Java用相同的方法在一个类中实现两个接口。哪种接口方法被覆盖?
Java 什么是Runtime.getRuntime()。totalMemory()和freeMemory()?
java.library.path中的java.lang.UnsatisfiedLinkError否*****。dll
JavaFX“位置是必需的。” 即使在同一包装中
Java 导入两个具有相同名称的类。怎么处理?
Java 是否应该在HttpServletResponse.getOutputStream()/。getWriter()上调用.close()?
Java RegEx元字符(。)和普通点?