Obsluga wyjatku rekurencyjnie ze zwracanym typem

0

Witam nawiązuje połączenie z baza ale czasami jest połączenie zerwane wiec postanowiłem po każdym wyjątku nawiązywać wtórnie połączenie ale o ile dobrze to wygląda w metodach gdzie nie zwraca sie wartości np.

public synchronized void metodaA(String wartosc){
    try {
		//jakies zapytanie do bazy bez zwracania wartosci
    }catch( Exception e ) {S_konsola.komunikat_Ex(e);  e.printStackTrace();
        installConnect(); //zerwanie i nawiazanie polaczenia
        metodaA(wartosc); //wywolanie motodyA
    }
}

to o tyle gorzej jest jak jest cos zwracane i metodaA np zwraca string bo po wywołaniu z wyjątku metodaA wartości zwrócone nie wiadomo gdzie zostana stracone? co polecacie? jak to rozwiązać?

0

Po pierwsze polecam to przemyśleć 1000x, bo taki kod jest naturalnym środowiskiem niebezpiecznych żyjątek zwanych Nieskończonymi Pętlami (tm).

Nie znam kontekstu i całego pomysłu, więc mogę się mylić, ale... Radziłbym nie używać tego typu bezwarunkowej rekurencji w bloku catch. Zamiast tego może spróbuj odświeżać połączenie co jakiś czas? A może już tak robisz? synchronized może sugerować użycie do tego osobnego wątku, tyle że w środku warto rozważyć jakiegoś sleepa. Albo zrobić ogranicznik w postaci licznika wywołań -- po np. 10 czy choćby 100 próbach ponownego połączenia niech funkcja się podda i rzuci ten wyjątek.

A jak sobie poradzić z tymi zwracanymi wartościami? Np. tak:

public synchronized String metodaB(String  wartosc){
    String result = null;
    try {
      //jakies zapytanie do bazy ze zwracaną wartością
      result = ...; // przypisanie wartości zwróconej przez zapytanie
    }catch (Exception e ) {
        S_konsola.komunikat_Ex(e); 
        e.printStackTrace();
        installConnect(); //zerwanie i nawiazanie polaczenia
        result = metodaB(wartosc);
    }
    return result;
}

Zamiast zmiennej result można użyć dwóch return.

Naprawdę, naprawdę zastanów się jednak nad tym wszystkim. Szczególnie jeśli chcesz zrobić z tego szablon dla wielu funkcji. Takie ubijanie wyjątków i -- potencjalnie -- wywoływanie z lasu nieskończonych rekurencji jest niebezpieczne.

PS. A tak w ogóle, jeśli chcesz to robić w ten sposób, to może lepiej użyć pętli z blokiem try-catch, a nie rekurencji? Łatwiej wprowadzić licznik wywołań, a kod będzie pewnie szybszy (prawdopodobnie nieistotne). W stylu:

public synchronized String metodaB(String  wartosc){
    String result = null;
    while (true) {
      try {
        result = metodaB(wartosc);
      } catch (Exception e) {
        S_konsola.komunikat_Ex(e); 
        e.printStackTrace();
        installConnect(); //zerwanie i nawiazanie polaczenia
      }
    }
    return result;
}

Zauważ proszę, że tutaj mamy nieeleganckie while (true), co obnaża nieskończoną pętlę i sugeruję, że z kodem prawdopodobnie jest coś nie tak. Maskowanie tego w rekurencji wcale nie pomoże ;).

0

Tak zgadza sie może sie to zapętlić ale aplikacja nie ma racji bytu jeśli straci połączenie z baza każdy wpis jest na wagę złota wiec lepiej jak cala aplikacja sie zawiesi do czasu połączenia z baza (pewnie zrobię opóźnienie np. 100ms by serwer nie był nadwyrężany)

przypadek w którym nawiązuje co jakiś czas połączenie jest dobry ale nie będę robił tego co chwile tylko co np. minutę nie chce tez obciążać łącza a pomiędzy 1 minuta może wysypać sie sporo zapytań takich bardziej ważnych

jeśli omine jakies zapytanie moze wprowadzać kolejne błędy i wszystko będzie powoli mylnie działać

ale oczywiście samo pytanie nie wyrzuci bledu bo będzie jeszcze w wewnętrznym try musze miec pewność ze każde zapytanie jest obsłużone w innym wypadku lepszy będzie stop calego serwera...

public synchronized void metodaA(String wartosc){
    try {    
        try {
                //jakies zapytanie do bazy bez zwracania wartosci
        }catch( Exception e ) {}
         
    }catch( Exception e ) {S_konsola.komunikat_Ex(e);  e.printStackTrace();
        installConnect(); //zerwanie i nawiazanie polaczenia
        metodaA(wartosc); //wywolanie motodyA
    }
}

Myślałem też by w wyjątku spisywać zapytanie i zrobić taka małą symulacje i np. gdy serwer połączy się do bazy to obsłuży wszystkie zapytania po kolei (jeśli chodzi o zapis) bo zaczytać nie zaczytam nic ale to co jest otwarte już będę mógł symulować dalej bez zbędnego przerywania… tylko stwarza to pewne problemy straty danych gdy nie nawiąże już więcej połączenia…

a tak à propos ten pomysł z result w wyjątku jak tak myślę, wydaje się całkiem sensowny dzięki :-)

0

Aplikacja faktycznie może nie mieć sensu gdy połączenia nie ma; czasem jedynym rozwiązaniem jest po prostu jej wyłączenie. Ciche przechwytywanie wyjątków, podczas gdy stało się coś bardzo złego, to zła praktyka. Jak zauważyłeś, aplikacja nie może w pewnych stanach kontynuować działania.

W tym wypadku można ew. przejść w stan oczekiwania na przywrócenie połączenia. Ale to nie znaczy, że program powinien wtedy -- zupełnie niepotrzebnie -- wyczerpywać zasoby komputera. Wprowadzenie opóźnienia, o którym wspomniałeś -- choćby niewielkiego -- może pomóc odciążyć procesor.

Zauważ jednak proszę, że gdy stosujesz rekurencje, to każde jedno wywołanie rekurencyjne powoduje alokację pamięci. Każdy element na stosie wywołania funkcji troszkę pamięci jednak zajmuję. Z tego powodu nieskończona rekurencja może wyczerpać zapas pamięci. Z wersją iteracyjną przynajmniej ten problem odpada.

Nie bardzo rozumiem, czemu w ostatnim przykładzie masz dwa zagnieżdżone bloki try? Jeśli w pierwszym catchu faktycznie nic się nie dzieje, to drugi nie zostanie nigdy wykonany.

0

pamięć by sie zwalniała gdy połączenie by sie nawiązało chociaż tu tez masz racje może warte by bylo to zastosowania

Z blokami try mylnie podszedłem do problemu...

dziękuję bardzo za pomoc :)

a tak na marginesie zastanawiam sie co gdy wystąpi blad w zapytaniu lub jakiś inny nie spodziewany? w pętli będzie wówczas chciał powtarzać to samo zapytanie i za każdym razem powstanie wyjątek? Bo try tez złapie inne wyjątki jeśli powstaną, można jakoś się przed tym zabezpieczyć i rozróżnić je? Czy jedynym w takiej sytuacji sposobem by było porównanie e.printStackTrace() ?

0

Takich informacji szukaj już w dokumentacji swojej bazy danych. Założę się, że przy braku połączenia nie rzuca ona wyjątkiem klasy Exception, tylko jakimś bardziej specyficznym. Może gdy brak połączenia rzuca wyjątkiem X, a w pozostałych przypadkach Y lub Z? W takiej sytuacji wystarczy przechwytywać nie Exception, tylko X.

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