11 marca 2007

Java Persistence - 3.7 Podsumowanie wyjątków

Rozdział 3.7 Summary of Exceptions jest przedstawieniem wyjątków zdefiniowanych przez specyfikację JPA. Wszystkie należą do pakietu javax.persistence.

PersistenceException - wyjątek rzucany przez dostawcę trwałości podczas wystąpienia sytuacji awaryjnej ogólnego typu. Może się pojawić w sytuacji wykonania operacji, która nie może się wykonać, np. z powodu braku połączenia do bazy danych.
PersistenceException jest klasą początkową hierarchii wyjątków JPA. Pojawienie się wyjątku PersistenceException i pochodnych powoduje wycofanie transakcji, poza NoResultException oraz NonUniqueResultException.
    try {
Persistence.createEntityManagerFactory("niezdefiniowanePU");
assert false : "Oczekiwano PersistenceException, ponieważ nezdefiniowanePU nie istnieje!";
} catch (PersistenceException oczekiwane) {
}
TransactionRequiredException - wyjątek rzucany przez dostawcę trwałości, kiedy transakcja jest wymagana, jednakże aktualnie niedostępna.

try {
Query query = em.createQuery("UPDATE Pracownik p SET p.imie = 'ZmianaImieniaWszystkim'");
query.executeUpdate();
assert false : "Oczekiwano TransactionRequiredException, ponieważ transakcja nieaktywna!";
} catch (TransactionRequiredException oczekiwane) {
}

OptimisticLockException - wyjątek rzucany przez dostawcę trwałości, kiedy wystąpi wyjątek związany z optymistycznym blokowaniem. Wyjatek może pojawić się podczas wywołania metody, synchronizacji (wywołanie metody flush) bądź ostatecznie podczas zatwierdzania transakcji.
Niestety nie wiem, jak przygotować test, aby zaprezentować wyjątek, więc go nie będzie.

RollbackException - wyjątek rzucany przez dostawcę trwałości, kiedy wywołanie EntityTransaction.commit() zakończy się niepowodzeniem.
Z braku pomysłów na test nie będzie go.

EntityExistsException - wyjątek rzucany przez dostawcę trwałości podczas wywołania metody persist z egzemplarzem encji, który znajduje się już w bazie danych (alternatywnie inny wyjątek PersistenceException może pojawić się zamiast EntityExistsException podczas zatwierdzania transakcji).

try {
Pracownik jacek = (Pracownik) em.createQuery(
"SELECT p FROM Pracownik p WHERE p.imie = 'Jacek' AND p.nazwisko = 'Laskowski'").getSingleResult();
Pracownik kopiaJacka = new Pracownik();
kopiaJacka.setNumer(jacek.getNumer()); // numer jest @Id
em.persist(kopiaJacka);
assert false : "Oczekiwano EntityExistsException, ponieważ encja już istnieje w bazie!";
} catch (EntityExistsException oczekiwane) {
}

EntityNotFoundException - wyjątek rzucany przez dostawcę trwałości, podczas wywołania operacji (np. dostęp do atrybutów) na referencji encji zwróconej przez metodę getReference, kiedy encja została w międzyczasie usunięta. Wyjątek EntityNotFoundException może się również pojawić, podczas wywołania metody refresh, kiedy encja nie istnieje już w bazie danych.

try {
assert em.getTransaction().isActive() == false;
Pracownik pracownikRef = em.getReference(Pracownik.class, 3);
pracownikRef.getImie();
assert false : "Oczekiwano EntityNotFoundException, ponieważ encja została skasowana a wykonano operację na jej referencji!";
} catch (EntityNotFoundException oczekiwane) {
}
EntityTransaction tx = null;
try {
assert em.getTransaction().isActive() == false;
tx = em.getTransaction();
tx.begin();
Pracownik jacek = (Pracownik) em.createQuery(
"SELECT p FROM Pracownik p WHERE p.imie = 'Jacek' AND p.nazwisko = 'Laskowski'").getSingleResult();
em.remove(jacek);
em.flush();
em.refresh(jacek);
jacek.getImie();
assert false : "Oczekiwano EntityNotFoundException, ponieważ encja została skasowana a wykonano operację na jej referencji!";
} catch (EntityNotFoundException oczekiwane) {
tx.rollback();
}

NoResultException - wyjątek rzucany przez dostawcę trwałości, podczas wywołania metody Query.getSingleResult, kiedy nie istnieje wynik zapytania.

try {
assert em.getTransaction().isActive() == false;
em.createQuery("SELECT p FROM Pracownik p WHERE p.nazwisko = 'NieIstnieje'").getSingleResult();
assert false : "Oczekiwano NoResultException, ponieważ nie istnieje pracownik o nazwisku NieIstnieje!";
} catch (NoResultException oczekiwane) {
}

NonUniqueResultException - wyjątek rzucany przez dostawcę trwałości, podczas wywołania metody Query.getSingleResult, kiedy istnieje więcej niż jedna encja w wyniku zapytania.

try {
assert em.getTransaction().isActive() == false;
utworzPracownika();
utworzPracownika();
Query query = em.createQuery("SELECT p FROM Pracownik p");
List pracownicy = query.getResultList();
assert pracownicy.size() > 1;
query.getSingleResult();
assert false : "Oczekiwano NonUniqueResultException, ponieważ zwracanych jest więcej encji niż jedna!";
} catch (NonUniqueResultException oczekiwane) {
}

3 komentarze:

  1. Uwaga.

    Pobrałem źródła javax.persistence korzystając z Maven. I od razu znalazłem błąd w komentarzu metody:

    getSingleResult()

    /**
    * Execute a SELECT query that returns a single result.
    * @return the result
    * @throws EntityNotFoundException if there is no result
    * @throws NonUniqueResultException if more than one result
    * @throws IllegalStateException if called for a Java
    * Persistence query language UPDATE or DELETE statement
    */
    public Object getSingleResult();


    Tymczasem specyfikacje mówi, o innych zwracanych wyjątkach:

    http://java.sun.com/javaee/5/docs/api/javax/persistence/Query.html#getSingleResult()


    W źródłach, zamiast EntityNotFoundException powinno być:
    NoResultException

    Nie wiem do kogo to zgłośić.

    OdpowiedzUsuń
  2. NoResultException - ktoś miał ciężkie dzieciństwo. Dla mnie taka sytuacja powinna być obsłuzona poprzez zwrócenie nulla

    OdpowiedzUsuń
  3. Po Twoim komentarzu jestem również zaskoczony takim rozwiązaniem. Nie zwróciłem uwagi na to wcześniej. Zastanawiam się, skąd pomysł na wyjątek vs null?! Uwagi odnośnie specyfikacji JPA można wysłać bezpośrednio do nich - jsr-318-comments@jcp.org (to już dla EJB 3.1). Warto również zapytać na grupach dostawców - OpenJPA, EclipseLink, Hibernate, itp. Daj znać, kiedy/jeśli coś się dowiesz w temacie.

    OdpowiedzUsuń