【问题标题】:Spring @Transactional - how to avoid specific exception from rolling back?Spring @Transactional - 如何避免特定异常回滚?
【发布时间】:2018-01-17 10:50:09
【问题描述】:

我有以下方法:

@Override
@Transactional(propagation = Propagation.REQUIRES_NEW, isolation = Isolation.SERIALIZABLE)
public void applyLog(int codFilial, List<LogLojaCentralCompactoEntity> items) {
}

内部调用:

@Override
@Transactional(noRollbackFor = PersistenceException.class)
public void apply(LogCompactoEntity entity) {
}

第二种方法有一个 try/catch 一个 PersistenceException。问题是事务回滚然后到达 PersistenceException。

我知道 Spring @Transactional 默认在任何未经检查的异常中回滚,但我明确告诉 noRollbackFor PersistenceException。

为什么它不起作用?有什么办法威胁它?

谢谢。

编辑 - apply 内部的 try/catch 方法是这样做的:

try {
   insert();
}
catch(PersistenceException e)
{
   update();
}

Edit2 - 日志:

Edit3 - 异常处理部分:

if (acao.equalsIgnoreCase("I")) {
    try {
        insertQuery.executeUpdate();
    }
    catch(PersistenceException e) {
        int affected = updateQuery.executeUpdate();

        if(affected == 0)
            throw new LogApplyException("O insert falhou e o update não afetou registros.");
    }
}

Edit4 - 更多信息:

1) 从 apply 中移除 @Transactional,将 @Transaction 仅留在 applyLog 结果上:

javax.persistence.PersistenceException: org.hibernate.exception.GenericJDBCException: 无法执行语句

2) 与 1 相同,但在此异常上添加 noRollbackFor = PersistenceException.class (on applyLog) 结果:

org.springframework.transaction.TransactionSystemException:无法提交 JPA 事务;嵌套异常是 javax.persistence.RollbackException: 事务标记为 rollbackOnly

编辑 5:

@lzagkaretos 解决方案是有效的(谢谢),但我想知道如何在未来的情况下处理这个问题。

【问题讨论】:

    标签: spring spring-boot


    【解决方案1】:

    更新

    我认为依靠主键违规异常来查找是否应该插入或更新记录不是您应该做的事情。您可以使用的另一种实现是在执行之前查找记录是否已保存在数据库中以执行更新或不执行插入。

    例如,如果您可以使用 spring 数据存储库,代码可能看起来像这样。

    public void apply(LogCompactoEntity entity) {
    
        LogCompactoEntity logCompactoEntity = (entity.getId() == null) ? new LogCompactoEntity() : logCompactoRepository.findOne(entity.getId());
        if (logCompactoEntity == null) {
            logCompactoEntity = new LogCompactoEntity();
        }
    
        copyProperties(entity, logCompactoEntity);
    
        logCompactoRepository.save(logCompactoEntity);
    }
    

    --

    也许您不应该在 apply 方法中使用 try/catch 块,并在方法签名中使用 throws PersistenceException 声明它。

    为了使noRollbackFor 工作,必须从apply 方法中抛出PersistenceException。您可以尝试以下方法。

    try {
        insert();
    }
    catch(PersistenceException e) {
        update();
        throw e;
    }
    

    【讨论】:

    • 不起作用。如果我在第一个方法上声明 noRollbackFor 它会抛出一个不同的异常: org.springframework.transaction.TransactionSystemException: 无法提交 JPA 事务;嵌套异常是 javax.persistence.RollbackException: 事务标记为 rollbackOnly
    • applyLog 调用适用于列表中的每个项目。数据库访问通过 JPA 申请。
    • 你想确保如果 PersistenceException 从insert() 方法抛出,执行继续并成功完成并提交数据库?
    • 是的,首先它会尝试插入(),如果因为键违规而引发 PersistenceException,那么它会调用 update()。
    • 那么,您可以简单地从apply() 中省略@Transactional(noRollbackFor = PersistenceException.class),只要您保留try - catch,如原帖所述。
    猜你喜欢
    • 2019-06-30
    • 2015-02-12
    • 2020-10-18
    • 2016-02-05
    • 1970-01-01
    • 1970-01-01
    • 2017-04-14
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多