2011-09-12 13 views
12

Używam EclipseLink w mojej aplikacji internetowej, a ja ciężko jest miło uchwycić i obsługiwać Wyjątki, które generuje. Widzę, że z podobnego problemu wydaje mi się this thread, ale nie widzę sposobu, aby go obejść lub naprawić.Jak wychwycić wyjątek naruszenia ograniczenia z EclipseLink?

Mój kod wygląda następująco:

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 
    } 
} 

Kiedy utrzymują() nazywa się podmiot, który narusza unikatowości, dostaję eksplozję wyjątkami, które zostały schwytane i rejestrowane przez kontener.

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) 

Próbowałem następujące:

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

Zdaję sobie sprawę, że za pomocą DataBaseException nie jest przenośny, ale trzeba od czegoś zacząć. Wyjątki nigdy nie zostaną złapane. Jakieś sugestie?

+0

co to znaczy "DataBaseException nie jest przenośny"? Dzięki! –

+0

@WeishiZeng Klasa DataBaseException jest zdefiniowana przez org.eclipse, a nie specyfikację JPA. Tak więc prawdopodobnie nie będzie działać (lub nawet skompilować) z innym dostawcą JPA. – AlanObject

Odpowiedz

8

Wygląda na to, że nie będę już podejmował żadnych działań w związku z tym pytaniem, dlatego opublikuję informacje o mojej pracy i zostawię to. Wiele wyszukiwań w Internecie nie znalazło wiele przydatnych informacji. Myślałem, że to podręcznik, ale żaden z tutoriali, które znalazłem, nie obejmuje tego tematu.

Jak się okazuje w tym stanie z EclipseLink The Wyjątek można złapać kiedy ograniczenie SQL jest łamane jest RollBackException który jest wynikiem em.commit() rozmowy. Więc zostały zmodyfikowane moich utrzymują metodę tak:

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

więc rozmówca łapie EntityExistsException i podejmuje odpowiednie działania. Dziennik nadal wypełnia wewnętrzne wyjątki, ale można go wyłączyć później.

Zdaję sobie sprawę, że jest to trochę nadużycie intencji EntityExistsException, który jest zwykle używany tylko wtedy, gdy pole ID jednostka jest ponownie wykorzystywany, ale na potrzeby aplikacji użytkownika nie ma znaczenia .

Jeśli ktoś ma lepsze podejście, opublikuj nową odpowiedź lub komentarz.

+1

Mam również do czynienia z tym problemem. Chcę wypreparować wyjątki ograniczenia sql (np. Nazwa zbyt długa, id istnieje, itp.). zamiast sprawdzać ograniczenie w moim kodzie. (co byłoby drogie w sprawdzeniu unikalnego identyfikatora). –

3

EclipseLink powinien wyrzucać tylko wyjątek PersitenceException lub RollbackException w zależności od środowiska i kolejności operacji, które wywołujemy w EntityManager. Jaki jest Twój poziom logowania? Prawdopodobnie widzisz te wyjątki rejestrowane przez EclipseLink, ale tylko zgłaszane jako przyczyny wyjątku RollbackException.

Można wyłączyć rejestrowanie wyjątków z właściwością PU, ale dla celów diagnostycznych lepiej jest zezwolić EclipseLink na rejestrowanie wyjątków.

+0

Tak jak mówisz, chcę zachować logowanie w trybie programowania, aby móc wykryć błędy systemowe, jeśli wystąpią. Ale prawdziwym problemem jest to, że kiedy wywołuję metodę ** commit() **, nie mogę wychwycić wyjątku, więc mogę wysłać komunikat na ekranie. – AlanObject

1

Używam Spring Boot 1.1.9 + EclipseLink 2.5.2. To jedyny sposób, w jaki mogę złapać wyjątek ConstraintViolationException. Zauważ, że moja handleError(ConstraintViolationException) jest bardzo prostą implementacją, która po prostu zwraca pierwsze stwierdzone naruszenie.

Należy zauważyć, że ten kod był również wymagany, gdy przełączyłem się na Hibernate 4.3.7 i Hibernate Validator 5.1.3.

Wygląda na to, że dodanie do mojej klasy JavaConfig klasy PersistenceExceptionTranslationPostProcessor exceptionTranslation() również nie przynosi żadnego efektu.


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

Używam tego produktu.

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

i moja funkcja z góry:

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

Dzięki, że nie trzeba programować walidacji dla każdego ustępują, jego powszechne w moich klas DAO.

+0

cokolwiek robisz, nie koduj w języku hiszpańskim :-D (zawsze angielski ..) – eav

1

Edycja persistence.xml dodając następującą właściwość:

nazwę właściwości value = "eclipselink.exception-handler" = "your.own.package.path.YourOwnExceptionHandler"

Teraz utworzyć YourOwnExceptionHandler klasy (na poprawnym opakowaniu). Wymaga implementacji org.eclipse.persistence.exceptions.ExceptionHandler.

Utwórz nieargumentowy konstruktor i wymaganą metodę handleException (...).

Wewnątrz tej metody można wychwycić wyjątki!

+0

wow, to jest całkiem niesamowita odpowiedź na 6-letni problem. Nie wydaje się to powszechną wiedzą. Spróbuję, kiedy ponownie otworzę ten projekt. – AlanObject

+0

Alan, udało mi się złapać wyjątki bazy danych i kody błędów. Nadal jednak próbuję wysłać dostosowaną wiadomość do mojej strony jsf. –