2011-09-12 15 views
12

Estoy usando EclipseLink en mi aplicación web, y estoy teniendo dificultades para atrapar y manejar Excepciones que genera. Veo desde this thread lo que parece ser un problema similar, pero no veo cómo solucionarlo o solucionarlo.¿Cómo atrapo la excepción de violación de restricción de EclipseLink?

Mi código es el siguiente:

public void persist(Category category) { 
    try { 
     utx.begin(); 
     em.persist(category); 
     utx.commit(); 
    } catch (RollbackException ex) { 
      // Log something 
    } catch (HeuristicMixedException ex) { 
      // Log something 
    } catch (HeuristicRollbackException ex) { 
      // Log something 
    } catch (SecurityException ex) { 
      // Log something 
    } catch (IllegalStateException ex) { 
      // Log something 
    } catch (NotSupportedException ex) { 
      // Log something 
    } catch (SystemException ex) { 
      // Log something 
    } 
} 

Cuando persisten() se llama con una entidad que viola una restricción de unicidad, consigo una explosión de excepciones que son capturados y registrados por el contenedor.

Exception [EclipseLink-4002] (Eclipse Persistence Services - 2.3.0.v20110604-r9504): 
    org.eclipse.persistence.exceptions.DatabaseException 
Internal Exception: java.sql.SQLIntegrityConstraintViolationException: The statement 
    was aborted because it would have caused a duplicate key value in a unique or 
    primary key constraint or unique index identified by 'SQL110911125638570' 
    defined on 'CATEGORY'. 
Error Code: -1 
(etc) 

he intentado lo siguiente:

try { 
     cc.persist(newCategory);   
    } catch (PersistenceException eee) { 
     // Never gets here 
     System.out.println("MaintCategory.doNewCateogry(): caught: " + eee); 
    } catch (DatabaseException dbe) { 
     // Never gets here neither 
     System.out.println("MaintCategory.doNewCateogry(): caught: " + dbe);    
    } 

que se dan cuenta de que el uso de DatabaseException no es portátil, pero tengo que empezar en alguna parte. Las excepciones nunca son atrapadas. ¿Alguna sugerencia?

+0

¿Qué significa "DataBaseException is not portable"? ¡Gracias! –

+0

@WeishiZeng La clase DataBaseException está definida por org.eclipse, no por la especificación JPA. Entonces esto probablemente no funcionaría (o incluso compilaría) con otro proveedor de JPA. – AlanObject

Respuesta

8

Parece que no voy a tener más actividad en esta pregunta, por lo que voy a publicar mi trabajo y dejarlo así. Varias búsquedas web no han encontrado mucho de lo que es útil. Hubiera pensado que este es un caso de libro de texto, pero ninguno de los tutoriales que he encontrado lo cubre.

Pues resulta que en esta condición con EclipseLink, la excepción se puede tomar cuando se viola la restricción de SQL es el RollBackException que es el resultado de la em.commit() llamada. Así que he modificado mi persistir método como este:

public void persist(Category category) throws EntityExistsException { 
    try { 
     utx.begin(); 
     em.persist(category); 
     utx.commit(); 
    } catch (RollbackException ex) { 
     Logger.getLogger(CategoryControl.class.getName()).log(Level.SEVERE, null, ex); 
     throw new EntityExistsException(ex); 
    } catch (HeuristicMixedException ex) { 
     Logger.getLogger(CategoryControl.class.getName()).log(Level.SEVERE, null, ex); 
    } catch (HeuristicRollbackException ex) { 
     Logger.getLogger(CategoryControl.class.getName()).log(Level.SEVERE, null, ex); 
    } catch (SecurityException ex) { 
     Logger.getLogger(CategoryControl.class.getName()).log(Level.SEVERE, null, ex); 
    } catch (IllegalStateException ex) { 
     Logger.getLogger(CategoryControl.class.getName()).log(Level.SEVERE, null, ex); 
    } catch (NotSupportedException ex) { 
     Logger.getLogger(CategoryControl.class.getName()).log(Level.SEVERE, null, ex); 
    } catch (SystemException ex) { 
     Logger.getLogger(CategoryControl.class.getName()).log(Level.SEVERE, null, ex); 
    } 
} 

así que la persona que llama atrapa el EntityExistsException y toma la acción apropiada. El registro todavía se llena con las excepciones internas, pero puede cerrarse más tarde.

que se dan cuenta de que esto es un poco de un abuso de la intención de la EntityExistsException que normalmente sólo se utiliza cuando se vuelve a utilizar un campo de ID de entidad, pero a los efectos de la aplicación de usuario no importa .

Si alguien tiene un mejor enfoque, publique una nueva respuesta o comentario.

+1

Me estoy enfrentando este problema también. Quiero destacar las excepciones de restricción de sql (por ejemplo, nombre demasiado largo, id exist, etc.). en lugar de verificar la restricción en mi código. (lo cual sería costoso verificar el id. único) –

3

EclipseLink solo debería arrojar una PersitenceException o una RollbackException dependiendo del entorno y el orden de las operaciones que está llamando en el EntityManager. ¿Cuál es su nivel de registro? Es probable que vea estas excepciones registradas por EclipseLink, pero solo lanzadas como causas de RollbackException.

Puede desactivar el registro de excepciones con la propiedad PU pero, por razones de diagnóstico, generalmente es mejor permitir que EclipseLink registre las excepciones.

+0

Como dices, quiero mantener el inicio de sesión durante el modo de desarrollo para poder detectar errores sistémicos si ocurren. Pero el verdadero problema es que cuando llamo al método ** commit() ** no puedo ver la excepción, así que puedo lanzar un mensaje en la pantalla. – AlanObject

1

Estoy usando Spring Boot 1.1.9 + EclipseLink 2.5.2. Esta es la única forma en que puedo atrapar a ConstraintViolationException. Tenga en cuenta que mi handleError(ConstraintViolationException) es una implementación muy simple que solo devuelve la primera violación que encuentra.

Tenga en cuenta que este código también fue necesario cuando cambié a Hibernate 4.3.7 y Hibernate Validator 5.1.3.

Parece que agregar PersistenceExceptionTranslationPostProcessor exceptionTranslation() a mi persistencia La clase JavaConfig tampoco tiene ningún efecto.


import javax.persistence.RollbackException; 
import javax.validation.ConstraintViolation; 
import javax.validation.ConstraintViolationException; 

import org.springframework.http.HttpStatus; 
import org.springframework.http.ResponseEntity; 
import org.springframework.transaction.TransactionSystemException; 
import org.springframework.web.bind.annotation.ControllerAdvice; 
import org.springframework.web.bind.annotation.ExceptionHandler; 

@ControllerAdvice 
class GlobalExceptionHandler 
{ 
    @ExceptionHandler(TransactionSystemException.class) 
    public ResponseEntity<Object> handleError(final TransactionSystemException tse) 
    { 
     if(tse.getCause() != null && tse.getCause() instanceof RollbackException) 
     { 
      final RollbackException re = (RollbackException) tse.getCause(); 

      if(re.getCause() != null && re.getCause() instanceof ConstraintViolationException) 
      { 
       return handleError((ConstraintViolationException) re.getCause()); 
      } 
     } 

     throw tse; 
    } 


    @ExceptionHandler(ConstraintViolationException.class) 
    @SuppressWarnings("unused") 
    public ResponseEntity<Object> handleError(final ConstraintViolationException cve) 
    { 
     for(final ConstraintViolation<?> v : cve.getConstraintViolations()) 
     { 
      return new ResponseEntity<Object>(new Object() 
      { 
       public String getErrorCode() 
       { 
        return "VALIDATION_ERROR"; 
       } 


       public String getMessage() 
       { 
        return v.getMessage(); 
       } 
      }, HttpStatus.BAD_REQUEST); 
     } 

     throw cve; 
    } 
} 
1

Yo uso este.

if (!ejbGuardia.findByPkCompuestaSiExiste(bean.getSipreTmpGuardiaPK())) { 
    ejbGuardia.persist(bean); 
    showMessage(ConstantesUtil.MENSAJE_RESPUESTA_CORRECTA, SEVERITY_INFO); 
} else { 
    showMessage("Excel : El registro ya existe. (" + bean.toString() + ") ", SEVERITY_ERROR); 
} 

y mi función de lo alto:

public boolean findByPkCompuestaSiExiste(Object clasePkHija) throws ClassNotFoundException { 
    if (null != em.find(this.clazz, clasePkHija)) { 
     return true; 
    } 
    return false; 
} 

Con que yo no tenga que programar una validación para cada persisten, su común en los mis clases DAO.

+0

lo que sea que estés haciendo, no codifiques en español :-D (siempre inglés ...) – eav

1

Editar su persistence.xml añadir la siguiente propiedad:

nombre de propiedad = valor "eclipselink.exception-handler" = "your.own.package.path.YourOwnExceptionHandler"

crear ahora la clase YourOwnExceptionHandler (en el paquete correcto). Requiere implementar org.eclipse.persistence.exceptions.ExceptionHandler.

Cree un constructor no argumento y el método requerido handleException (...).

¡Dentro de este método, puede ver las excepciones!

+0

guau que es una respuesta bastante sorprendente a un problema de 6 años. Esto no parece ser de conocimiento común. Voy a intentarlo cuando vuelva a abrir ese proyecto. – AlanObject

+0

Alan, pude ver las excepciones de la base de datos y los códigos de error. Sin embargo, todavía estoy tratando de enviar un mensaje personalizado a mi página jsf. –

Cuestiones relacionadas