Obsługa wyjątków JPA.

0

Witam. Tak się zastanawiam, czy przy operacjach na encjach takich jak zapis, edycja, odczyt należy łapać wyjątki? Np. operacja zapisu może się nie powieść itp? Dajmy na to takiego persista, merge czy remove. Czy należy umieszczać to w bloku try catch i łapać jakiś wyjątek JPA? Jak to wygląda w profesjonalnych aplikacjach?

	@Override
	public void createUser(User user) {
		entityManager.persist(user);
	} 

Druga sprawa to mam np. metodę, która zwraca listę:

	@SuppressWarnings("unchecked")
	@Override
	public List<Transfer> getTransferAccount(int id) {
		Query query = entityManager
				.createQuery("select t from Transfer t where t.userAccountFrom.id = :id or t.userAccountTo.id = :id order by t.data DESC");
		query.setParameter("id", id);
		List<Transfer> transfers = query.getResultList();
		return transfers;
	}

Kompilator ostrzega, żeby dodać adnotację suppressWarnings ze względu na niepewną konwersję. Robi się to może inaczej? Czy trzeba koniecznie dodawać tą adnotację? Czy może po prostu pominąć to ostrzeżenie o dodaniu suppreswarnings i nie dodawać tej adnotacji. Tylko, że wtedy mam podobny problem ze zwracaniem pustej listy jak w niżej opisanym przykładzie o pojedynczym rekordzie.

Gdy zwracam pojedynczy rekord to wystarczy rzutowanie i mogę uniknąć suppresWarnings, jednak muszę taki kod umieszczać w bloku try catch inaczej wywali mi błąd null pointer exception. Tylko, że to nie bardzo jest jakaś sytuacja wyjątkowa, bo zapytanie może zwrócić nulla bo po prostu nie ma takiej daty. I tak ostatecznie wychodzi taki zbędny try catch. W catchu to właściwie nie ma czego obsługiwać bo to żaden błąd z punktu widzenia aplikacji, że nie zwróciło daty. Jak należy takie sytuacje obsłużyć? Trochę chaotycznie to opisałem, ale myślę, że wiadomo o co chodzi.

	@Override
	public Date getLastTransaction(int id) {
		Date lastTransfer = null;

		try {
			Query query = entityManager
					.createQuery("select max(t.data) from Transfer t where t.userAccountFrom.id = :id");
			query.setParameter("id", id);
			lastTransfer = (Date) query.getSingleResult();

		} catch (Exception e) {
			System.out.println(e.getMessage());
		}
		return lastTransfer;
	} 
0

Pomoże ktoś?

1
  1. Jak są checked to trzeba łapać bo oczywiście że operacja na bazie może nie zadziałać. Jak są runtime to nie musisz bo JPA samo sobie będzie obsługiwać to robić rollback.
  2. Można to zrobić inaczej -> na przykład przez Criteria API.
1

Ad1.
Tutaj musisz sobie sam odpowiedzieć. Generalnie da się przewidzieć każdą sytuację i np. nie duplikować zapisu. Z drugiej strony mogą wylecieć hardcorowe wyjątki takie jak brak miejsca na dysku dla bazy danych. Wtedy musisz go złapać i dać jakiś sensowny komunikat dla odbiorcy. Oczywiście musisz robić wszystko bardzo świadomie ze względu na transakcje które są zapięte i muszą być prawidłowo wycofane.

Ad2.
Istnieje wersja metody createQuery/createNativeQuery która przyjmuje jako drugi parametr klasę obiektu którego się spodziewasz. Wtedy zamiast standardowego Query zwraca Ci TypedQuery i dalej już nie ma co tłumaczyć bo problemu też nie ma :).

0
krzysiek050 napisał(a):

Ad2.
Istnieje wersja metody createQuery/createNativeQuery która przyjmuje jako drugi parametr klasę obiektu którego się spodziewasz. Wtedy zamiast standardowego Query zwraca Ci TypedQuery i dalej już nie ma co tłumaczyć bo problemu też nie ma :).

Faktycznie dzięki, ale to rozwiązuje sprawę z suppresWarnings. Problem z nullem w przypadku braku rezultatu dla singleresult nadal pozostaje i muszę to łapać w try catch, tylko w sumie nie wiadomo co z tym wyjątkiem robić. Zostawiać takie pustego catcha?

0

Ale wtedy przecież dostajesz już obiekt takiego typu jaki chcesz i nie musisz rzutować przez co cały try catch jest do wywalenia.

0
krzysiek050 napisał(a):

Ale wtedy przecież dostajesz już obiekt takiego typu jaki chcesz i nie musisz rzutować przez co cały try catch jest do wywalenia.

Nie rozumiemy się, chyba coś źle wyjaśniłem. Chodzi o to, że moje zapytanie może nie zwrócić żadnego wyniku i z punktu widzenia poprawności aplikacji nie jest to żaden błąd. Przykładowo kiedy dodaję użytkownika to sprawdzam czy nie ma już w bazie podanego loginu. Jeśli nie ma to zapytanie nic nie zwraca. Z tego co wyczytałem to trzeba to umieszczać i nie da się tego jakoś ominąć mimo iż to bezsensowne.

1

public List<Transfer> getTransferAccoun ? no to jak twoje zapytanie niczego nie znajdzie no to zwracasz pustą listę. to i tak jest komfortowo, bo przez iteracje możesz mieć na to ***ane ;] . jeżeli chodzi o date no to z dao jak nie znajdzie możesz po prostu zwrócić nulla, wtedy gdzieś wyżej jeżeli będziesz chciał wykonać na zwróconej dacie jakąś metodę wystarczy, że sprawdzisz po prostu czy !=null. co do wyjątków typu hardcorowe wyjątki takie jak brak miejsca na dysku dla bazy danych to nwm po co takie łapać.

1

@olek1
Jeżeli wiesz że coś może zwrócić null to nie operujesz bezpośrednio na wartości i czekasz na wyjątek tylko sprawdzasz czy result==null.
Dla takiej sytuacji jak powiedziałeś możesz zrobić:

User result = query.getSingleResult();
if(user!=null){ // login zajęty
    throw new UserAlreadyExist();
}
//dalej twórz konto 
 

To jest takie miękkie sprawdzenie. Później i tak musisz sprawdzić czy przy zapisywaniu nie poleci ci unique constraint exception z bazy danych gdy masz optimistic locking i ktoś spróbuje prawie w tym samym czasie stworzyć użytkownika z tymi samymi loginami.

co do wyjątków typu hardcorowe wyjątki takie jak brak miejsca na dysku dla bazy danych to nwm po co takie łapać.

Żeby użytkownik końcowy nie dostał paskudnego ekranu błędu ze szczegółami tylko piękny z napisem "Wystąpił błąd systemu.". Może to być nawet łapane w Controller Advice ze Springa, ale jednak warto.

0
krzysiek050 napisał(a):

@olek1
Jeżeli wiesz że coś może zwrócić null to nie operujesz bezpośrednio na wartości i czekasz na wyjątek tylko sprawdzasz czy result==null.
Dla takiej sytuacji jak powiedziałeś możesz zrobić:

User result = query.getSingleResult();
if(user!=null){ // login zajęty
    throw new UserAlreadyExist();
}
//dalej twórz konto 
 

To jest takie miękkie sprawdzenie. Później i tak musisz sprawdzić czy przy zapisywaniu nie poleci ci unique constraint exception z bazy danych gdy masz optimistic locking i ktoś spróbuje prawie w tym samym czasie stworzyć użytkownika z tymi samymi loginami.
.

Ok, ale to nie o to chodzi. Samo wywołanie

query.getSingleResult(); 

jeśli zwróci null rzuca wyjątek, nie chodzi potem o operacje na zmiennej do jakiej przypiszemy wynik. Z tego co wyczytałem obejść się tego nie da i trzeba dawać try catch chyba, że użyjemy listy zamiast pojedynczego wyniku mimo iż spodziewamy się jednego rekordu.

1 użytkowników online, w tym zalogowanych: 0, gości: 1