2012-04-17 22 views
5

Estoy usando JPA con Hibernate como proveedor con transacciones manejadas por contenedor (JBoss AS 6.1.0.Final).Manejo de excepciones con JPA + Hibernate

Estoy tratando de implementar un manejo de excepciones muy detallado porque tengo una jerarquía de excepciones particular en mi aplicación para poder definir qué hacer en cada situación. Por lo tanto, he estado investigando durante horas y encuentro que la documentación es vaga y los ejemplos un poco crudos porque el manejo de excepciones siempre se omite "por el bien de la claridad" o es un simple bloque try-catch que maneja Exception e.

Por ejemplo, tome este código:

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"); 
    } 
} 

El bloque catch está en blanco porque ahí es donde estoy atascado ... no sé qué excepción debería tomar para alertar al sistema que el usuario estaba intentando eliminar un registro inexistente.

Mi pregunta concreta es: ¿Puedo detectar excepciones de Hibernate en ese bloque catch o tengo que atrapar las JPA? Encontré algunas fuentes que afirman que JPA envuelve las excepciones de los proveedores, pero eso me suena extraño. También descubrí que al llamar al método flush() es posible detectar las excepciones de manipulación y acceso a la base de datos, ya que el contenedor administra las transacciones y, por lo tanto, el compromiso entra en más pasos luego de invocar deleteCompany.

Gracias.

EDIT: Estoy arreglando las excepciones que capto con mis propias excepciones anotadas con @ApplicationException (rollback = true), para poder lanzarlas de nuevo y manejarlas más claramente.

EDIT 2: He actualizado mi código. La fusión antes de la eliminación persiste en la empresa si no está en la base de datos, lo que hace que la eliminación sea exitosa en todo momento. Ahora se lanzan las excepciones y estoy probando cómo se comporta en diferentes situaciones atrapando las excepciones de JPA como lo sugiere Perception.

EDIT 3: Ahora está funcionando! Resulta que el error estaba parcialmente en mi código debido a esa llamada de fusión. Obtener la referencia primero y luego intentar eliminarlo es el truco, de esa forma pude capturar una EntityNotFoundException, envolverla y lanzarla de nuevo.

Respuesta

5

Definitivamente no captarás las excepciones de los proveedores porque se incluyen en las excepciones de JPA. Tenga en cuenta que usted podría estar recibiendo uno de los varios tipos de excepción en el punto en cuestión:

  • IllegalArgumentException - por separado o de objetos no-entidad
  • IllegalStateException - gestor de la entidad está cerrado
  • PersistenceException - al menos, algunos subclase de los mismos. Puede obtener esto para cualquier número de razones, si no hay ninguna transacción asociada y la llamada requiere una, si una restricción de la base de datos rechaza la operación , si la transacción se lleva demasiado tiempo, etc, etc

Realmente no debería capturar estas excepciones en un nivel tan bajo, a menos que planee volver a envolverlas en una excepción de aplicación personalizada de algún tipo. Si decide seguir esa ruta, asegúrese de ajustar la excepción original para que el seguimiento de la pila no se pierda.

Vale la pena observar que todas las excepciones generadas por el Administrador de entidad JPA son excepciones de tiempo de ejecución.

+0

Bonito consejo el que das aquí, no sabía que todos los temas eran excepciones de tiempo de ejecución, pero parece razonable pensar en las transacciones manejadas por contenedor y la reversión relacionada. Los atraparé y los envolveré en mis propias excepciones para arrojarlos de nuevo, pero también preservaré la excepción original. Solo una cosa ... ¿podré determinar la excepción en particular si capturo la PersistenceException? o es esta identificación un mal enfoque? – Gamb

+1

Usted * puede * obtener la excepción del proveedor (se incluirá en la excepción de persistencia como 'causa '), pero no es una buena idea por varias razones. 1) No debe preocuparse por el proveedor, quiere poder cambiar de proveedor a voluntad sin cambiar su código. 2) Las implementaciones de los proveedores no siempre están bien documentadas, por lo que tratar de determinar el conjunto completo de excepciones puede ser un ejercicio inútil. – Perception

+0

Ya veo. Perdón por molestar, pero aún no veo cómo voy a poder determinar si un objeto no se almacenó en la base de datos cuando invoco este método ... Encontré [este sitio] (http: //www.objectdb .com/api/java/jpa/exceptions) que se supone que enumera todas las excepciones JPA y la que parece ajustarse a mi dilema es javax.persistence.EntityNotFuundException, pero no aclara si será lanzado por un entityManager.remove() llame ... – Gamb