Java Spring数据异常处理

Java Spring数据异常处理,java,spring,spring-data,spring-data-jpa,Java,Spring,Spring Data,Spring Data Jpa,我正在从事一个使用SpringDataJPA的项目。我需要处理JpaRepository方法调用中的一些异常 在下面的代码中,我需要截获主键违规错误,但无法直接捕获异常。在我的例子中,当发生此类异常时,UnexpectedRollbackException异常由存储库层(JpaRepository)抛出。我需要在这个异常对象内部进行搜索,以确定问题的原因 我想知道是否有一个更“优雅”的方式来实现这一点 public Phone insert(Phone phone) throws Busines

我正在从事一个使用SpringDataJPA的项目。我需要处理JpaRepository方法调用中的一些异常

在下面的代码中,我需要截获主键违规错误,但无法直接捕获异常。在我的例子中,当发生此类异常时,UnexpectedRollbackException异常由存储库层(JpaRepository)抛出。我需要在这个异常对象内部进行搜索,以确定问题的原因

我想知道是否有一个更“优雅”的方式来实现这一点

public Phone insert(Phone phone) throws BusinessException {
    Phone result = null;
    try{
        result = phoneRepository.save(phone);
    }
    catch(UnexpectedRollbackException ex){
        if((ex.getCause() != null && ex.getCause() instanceof RollbackException) &&
           (ex.getCause().getCause() != null && ex.getCause().getCause() instanceof PersistenceException) && 
           (ex.getCause().getCause().getCause() != null && ex.getCause().getCause().getCause() instanceof ConstraintViolationException)){
                throw new BusinessException("constraint violation", ex);
        }
    }
    catch(Exception ex){
        throw new OuvidorNegocioException("unknown error", ex);
    }       
    return result;
}
谢谢

更新:

下面的代码似乎要好得多

public Phone insert(Phone phone) throws BusinessException {
    Phone result = null;
    try{
        result = phoneRepository.save(phone);
    }
    catch(UnexpectedRollbackException ex){
        if(ex.getMostSpecificCause() instanceof SQLIntegrityConstraintViolationException){
                throw new BusinessException("constraint violation", ex);
        }
    }
    catch(Exception ex){
        throw new OuvidorNegocioException("unknown error", ex);
    }       
    return result;
}

无论您在哪里处理异常,都可以选择查看
getmosspecificcause()
getRootCause()
方法的
UnexpectedRollbackException
。关于这些方法。

和其他对你的问题发表评论的人一样,我也认为你在文章中提出的解决方案是一个糟糕的解决方案。存储库抽象的唯一目的是隐藏持久性机制,以便客户端不必知道它。在您的例子中,您寻找一个低级SQL异常,它被Spring和JPA有意抽象掉了


如果确实要处理约束冲突,则要捕获的正确选项是
DataIntegrityViolationException
。存储库将在Spring
DataAccessException
子类型中包装特定于存储的(MongoDB、JPA,无论您使用什么)以允许客户端准确地执行以下操作:捕获每个错误类型的异常,而不是每个持久性机制的异常。

我不同意这种方法。让Spring数据异常从数据层抛出,并让服务/业务层处理它。你通过这种方式捕捉和重新聚集,发送的信息越来越少。嗯。。。我真的不这么认为。此代码已在我的业务/服务层中。我的客户端层(html/javascript)只需要知道违反了“主键约束”。如果没有必要,为什么要发送所有异常结构?很好。GetMostSpecificCase()就是我要找的。这似乎解决了我的问题。谢谢,很乐意帮忙。祝你的项目好运!谢谢你,吉尔克。我明白你的意思。我已经尝试过了,但在我的例子中,服务层中的insert()方法将始终注册到事务中(Propagation.REQUIRES_NEW)。因此,生成的异常将是TransactionException的子类型的UnexpectedRollbackException。DataAccessException位于另一个类层次结构中。catch to DataIntegrityViolationException异常将永远不会被处理。有趣的是……查看Spring中的事务管理代码,唯一的可能性是,
未预料的回滚异常
可能会发生,其原因是JTA基础设施抛出了异常,而不是存储库。那么,您首先必须使用JTA事务的原因是什么呢?我需要在事务中注册操作(插入/更新),因为它涉及其他实体中的修改。因此,在服务层中,该方法使用@Transactional(propagation=propagation.REQUIRES_NEW)属性修饰。调用存储库时,它的操作在事务中。您是否有可能将
意外回滚异常的堆栈跟踪添加到问题中?这里的局势非常可疑。如果您确实使用
@Transactional
注释了
insert(…)
,并且事务确实在此处开始(请检查您的tx配置),则存储库调用不会导致事务异常(因为此时实际上没有调用任何事务功能)。所以没有堆栈跟踪(还有更精确的事务设置文档,很难判断发生了什么。如果数据库在一个表上有多个约束,则保存可能会在其中任何一个约束上失败。如果服务层捕捉到spring数据异常,它如何识别哪个约束?我甚至不会将此异常处理在服务中,但移动到存储库层并抛出特定的异常。使用SpringDataRespository,我们如何用这些可抛出的异常标记存储库?