我正在开发一个在glassfish v3上运行的EJB应用程序。如果我查看EntityManager类的javadoc,它会说像find,persist等方法抛出从PersistenceException派生的异常。但是,在实践中我注意到,如果在数据库级别出现问题(例如,找不到表),则可能抛出从org.eclipse.persistence.exceptions.DatabaseException派生的异常。所以我正确地假设除了标准的持久性异常之外,我还必须处理由我使用的任何持久性提供程序引发的异常?这往往意味着我需要编写特定于我选择的JPA提供程序的错误代码,如果我稍后更改为另一个,我需要更改我的代码以捕获不同的异常类,如HibernateException。
答案 0 :(得分:6)
在我看来,你应该只处理标准JPA异常层次结构中的异常(除非你想处理规范没有标准异常的特定情况,在这种情况下你的应用程序不会便携式 - 但我想不出任何问题。 EJB 3.0 JPA规范(JSR 220)在3.7节中总结了它们:
3.7例外摘要
以下是摘要 由此定义的例外 规格:
PersistenceException
抛出
PersistenceException
由持久性提供者提供的时候 出现问题。它可能是 抛出报告调用 操作无法完成,因为 意外错误(例如,失败 持久性提供程序打开一个 数据库连接) 所有其他 由此定义的例外 规范是。的子类PersistenceException
。所有实例PersistenceException
除外NoResultException
和。{的实例NonUniqueResultException
会导致 当前的交易,如果是的话 有效,标记为回滚。
TransactionRequiredException
TransactionRequiredException是 由持久性提供程序抛出 当需要交易但是 不活跃。
OptimisticLockException
OptimisticLockException
是 由持久性提供程序抛出 当一个乐观的锁定冲突 发生。可能会抛出此异常 作为API调用的一部分,在flush,或 在提交时。目前 交易,如果一个是活跃的,将是 标记为回滚。
RollbackException
RollbackException
被抛出 持久性提供者何时EntityTransaction.commit
失败。
EntityExistsException
EntityExistsException
可能会抛出 由持久性提供者提供的 调用perist操作和 实体已经存在。该 可能会抛出EntityExistsException
当调用持久化操作时, 或EntityExistsException
或 另一个PersistenceException
可能是 在提交时抛出。
EntityNotFoundException
EntityNotFoundException
是 由持久性提供程序抛出 当获得的实体参考时 访问getReference
但是 实体不存在。也是 刷新操作时抛出的 该实体不再存在于 数据库。当前的交易,如果 一个是活跃的,将被标记为 回滚。
NoResultException
NoResultException
被抛出 持久性提供者何时 调用Query.getSingleResult
并且 没有结果可以返回。这个 异常不会导致当前 交易,如果一个人是活跃的,那就是 标记为回滚。
NonUniqueResultException
NonUniqueResultException
是 由持久性提供程序抛出 当Query.getSingleResult
时 调用,并且有多个 查询的结果。这个例外 不会引起潮流 交易,如果一个人是活跃的,那就是 标记为回滚。
对我来说,特定于提供者的异常是“内部”的东西,大部分时间都用于表示技术问题,即应用程序中应该修复的错误(例如,如果缺少表,则是错误,修复它,它不会'有意义地处理这种异常)。
答案 1 :(得分:1)
我做了一些更多的实验。当我切换到Hibernate时,我发现如果我在bean中捕获异常调用EntityManager方法作为Throwable,那么如果发生的事情超出PersistenceException子类支持的情况(例如缺少一个表),那么HibernateException包含在一个普通的Persistence Exception中,这是有道理的。如果你想知道持久性是否出错,你可以捕获PersistenceException。
在TopLink的情况下,我直接收到了Eclipse DatabaseException。这对我来说似乎是个错误 - 正如Pascal所提到的,应该没有必要捕获提供者特定的异常。我将为Glassfish制作一个错误报告,并在此处发布一个指向结果的链接。
在这两种情况下,如果没有在EntityManager的站点上捕获异常,那么异常将被捕获并作为容器更常见的东西被重新抛出,例如EJBException或TransactionRolledBackException,并且在大多数情况下捕获这些异常更有意义。
答案 2 :(得分:0)
这通常是Spring框架将特定于实现的异常转换为与实现无关的异常的原因。如果您担心捕获“内部”异常类型的耦合,您可以在持久层中编写异常代理代码以捕获DatabaseException
并重新抛出您自己的ShanesPersistenceException extends RuntimeException
(或其他),并将原始异常包括在内原因。然后,如果您稍后切换实现,则只需触摸异常代理即可为新供应商的异常添加catch-and-rethrow。