使用JPA + Hibernate进行异常处理

5

我正在使用JPA,Hibernate作为提供程序,并使用容器管理的事务(JBoss AS 6.1.0.Final)。

我尝试实现一些细粒度的异常处理,因为我的应用程序有一个特定的异常层次结构,所以我可以定义在每种情况下该怎么做。因此,我已经调查了几个小时,发现文档模糊不清,示例有些简陋,因为异常处理总是被省略“为了清晰起见”,或者是一个简单的try-catch块来处理Exception e。

例如,看看这段代码:

public void deleteCompany(ICompany company) throws MyException1, MyException2 {
    if(entityManager != null){
        if(company !=null) {
            try {
                ICompany companyReference= entityManager.getReference(Company.class, company.getId());
                entityManager.remove(managedCompany);
                entityManager.flush();
            } catch(EntityNotFoundException companyDoesNotExist) {
                //Wrap & Throw
            }
        } else {
        throw new MyException1("An error occurred while attempting to save a null instance of a company");
        }
    } else {
        throw new MyException2("The entity manager instance is null");
    }   
}

捕获块为空,因为我卡在这里了……我不知道应该捕获哪个异常来警告系统用户试图删除不存在的记录。
我的具体问题是:我能在那个catch块中捕获Hibernate异常吗?还是必须捕获JPA异常?我找到了一些来源声称JPA包装提供程序的异常,但这对我来说听起来很奇怪。我还发现调用flush()方法可以捕获数据库访问和操作异常,因为事务由容器管理,因此提交在调用deleteCompany之后进一步进行。
谢谢。
编辑:我使用@ApplicationException(rollback=true)注释标记自己捕获的异常,以便再次抛出并更清晰地处理它们。
编辑2:我已更新我的代码。删除公司之前的合并会使公司在数据库中不存在,则每次删除都成功。现在正在测试在不同情况下捕获JPA异常的行为建议。
编辑3:现在它正常工作了!结果错误部分在于我的代码,因为那个合并调用。首先获取引用,然后尝试删除即可完成此操作,这样我就能够捕获EntityNotFoundException,将其包装并再次抛出。
1个回答

5
您肯定不会捕获供应商异常,因为它们会转换为JPA异常。请注意,在此时您可能会收到几种异常类型之一:
- IllegalArgumentException - 对于分离或非实体对象 - IllegalStateException - 实体管理器已关闭 - PersistenceException - 至少有某个子类。如果没有相关联的事务并且调用需要一个,则可以由于任何数量的原因而出现此异常,如果数据库约束拒绝操作,如果事务时间太长等等。
除非您计划重新封装成自定义应用程序异常,否则您真的不应该在这个低级别上捕获这些异常。如果您决定采取这种方法,请确保包装原始异常,以便不会丢失堆栈跟踪。
值得注意的是,JPA实体管理器生成的所有异常都是运行时异常。

你提供的这个技巧很不错,我之前并不知道它们都是运行时异常,但考虑到容器管理的事务和相关回滚,这听起来很合理。我会捕获它们并将它们包装在我的自定义异常中再次抛出,但我也会保留原始异常。只有一个问题...如果我捕获PersistenceException,我能确定具体的异常吗?或者这种识别方式是错误的? - Fritz
1
可以获取供应商异常(它将被包装在持久性异常中作为cause),但出于几个原因,这不是一个好主意。1)你不应该关心供应商,你希望能够随意更改供应商而不更改代码。2)供应商实现并不总是有很好的文档记录,因此尝试确定完整的异常集可能是徒劳的练习。 - Perception
我明白了。很抱歉打扰您,但我仍然不明白如何确定在调用此方法时对象是否未存储在数据库中... 我找到了这个网站,它应该列出所有的JPA异常,而似乎适合我的困境的是javax.persistence.EntityNotFoundException,但它并没有说明它是否会被entityManager.remove()调用抛出... - Fritz
我更新了我的问题并指向了我找到的解决方案。@Perception 感谢您提供的提示和我所需的线索(不要捕获供应商异常+ JPA包装异常+由EM生成的所有异常都是运行时异常)。 - Fritz

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接