2013-05-13 20 views
6

Tworzę pliki JDBC Statement i ResultSet.Upewnij się, że obiekty są zamknięte, jeśli zostanie zgłoszony wyjątek.

Findbugs słusznie zwraca uwagę, że nie podaję tych close, jeśli zostanie zgłoszony wyjątek.

Więc teraz mam:

Statement stmt = null; 
ResultSet res = null; 
try { 
    stmt = ... 
    res = stmt.executeQuery(...); 
    ... 
} finally { 
    try { 
     if(res != null) 
      res.close(); // <-- can throw SQLException 
    } finally { 
     if(stmt != null) 
      stmt.close(); 
    } 
} 

(Tylko mam raczej więcej zestawów wynik i przygotowane oświadczeń i tak dalej otwarty ... więc moja zagnieżdżanie finally s jest raczej głębiej)

Nie ma w lepszy sposób, aby zapewnić, że duża liczba zestawów wyników zostanie zamknięta?

(Na marginesie: w Symbian nigdy nie pozwolili destruktory/zamknij/odblokowanie/usuń metody -Type rzucać żadnych błędów Myślę, że to bardzo dobra decyzja projekt, który wszyscy close metody JDBC może rzucać SQLException sprawia, że ​​rzeczy niepotrzebnie skomplikowane.. w mojej opinii.)

+3

dlaczego masz 'try-finally' w swoim' końcu'? powinno być trochę 'catch' .... prawda? – Bill

+2

Co powiesz na przechowywanie wszystkich zestawów i zestawów wyników na liście i powtarzanie ich na listach? – reporter

+2

@Bill: W przypadku pierwszego "zamknięcia" zgłasza wyjątek. –

Odpowiedz

4

Jeśli używasz Java 7, możesz skorzystać z faktu, że ResultSet rozszerza AutoCloseable i używa instrukcji try-with-resources.

try (Statement sql = <WHATEVER>; 
    ResultsSet res = sql.executeQuery(<WHATEVER>)) { 
    // Use results 
} 

Przynajmniej wtedy można uniknąć klauzul finally.

+2

Niestety produkcja utknęła w punkcie 1.6 :(Ale podoba mi się to podejście, które mi pokazałeś i to by dokładnie rozwiązało te problemy – Will

+1

@Will Dzięki za edycję. * Zastanawiam się jak rzadko zdarza się, aby OP edytował i poprawiał odpowiedzi na pytania * :-) –

3

W kodzie, gdzie mogę polegać na Javie 7, prawdopodobnie użyłbym try-with-resources jako suggested by Duncan Jones. w tej formie

Pierwszy to zestaw metod pomocniczych na statycznej klasy pomocnika,::

W moim starszym kodzie, istnieją dwa podejścia, jakie stosowane

public static final Statement quietClose(Statement s) { 
    if (s != null) { 
     try { 
      s.close(); 
     } 
     catch (Exception e) { 
      // Do some useful logging here 
     } 
    } 
    return null; 
} 

Następnie w finally blok:

stmt = Helper.quietClose(stmt); 

drugie podejście było użyć LinkedList, dodać do niego rzeczy w kolejności, w jakiej je otworzyłem, a następnie mieć on lper, który zapętlony w odwrotnej kolejności i zasadniczo zrobił powyższe.


We wszystkich przypadkach staram się zachować sposobów na tyle krótki, że nie kończy się z 18 różnych obiektów JDBC że muszę zamknąć. (Mówię, że "staram się" ... nie zawsze mi się to udaje).

0

Aby rozwinąć sugerowane reporter, należy zachować listę elementów do zamknięcia. Utwórz metodę wykonywania zamknięcia, które przechwytuje Throwable i zwraca wartość Throwable. Iteruj listę, zbierając wszystkie zwrócone i zwróć pierwszą zwróconą.

private Throwable close(Closable c){ 
    try{ 
     c.cloase(); 
     return null; 
    } catch (Throwable t){ 
     return t; 
    }; 
} 

private void workMethod(){ 
    try{ 


    }finally{ 
     List<Throwable> ts = new ArrayList<Throwable>(); 
     for(Closable c : closables){ 
      Throwable T = close(c); 
      if (t != null) 
        ts.add(t); 
     } 

     if (!ts.isEmpty()) 
      throw ts.get(0); 
    } 
} 
2

A blog post by David M. Lloyd od kilku lat zajmuje to dobrze, badając opcje i rozliczania na wzór gniazdowania nowy try/finally bezpośrednio powyżej każdego zasobu, który jest tworzony.W naszym przykładzie, coś takiego:

Statement stmt = null; 
ResultsSet res = null; 
try { 
    stmt = ... 
    try { 
     res = stmt.executeQuery(...); 
     ... 
    } finally { 
     try { 
      res.close(); 
     } catch (Throwable t) { 
      t.printStackTrace(); 
     } 
    } 
} finally { 
    try { 
     stmt.close(); 
    } catch (Throwable t) { 
     t.printStackTrace(); 
    } 
} 

Jeśli pójdziesz tą drogą, to jest dobry pomysł, aby również śledzić informacje Dawida i stworzyć bezpieczną metodę zamykania zasobów, które można wykorzystać w całym projekcie. Ta metoda może być następnie wywołana w miejsce bloków try/catch w blokach .

// put this anywhere you like in your common code. 
public static void safeClose(Closeable c) { 
    try { 
     c.close(); 
    } catch (Throwable t) { 
     // Resource close failed! There's only one thing we can do: 
     // Log the exception using your favorite logging framework 
     t.printStackTrace(); 
    } 
} 
3

Zamiast pisać to sam, sprawdź Apache Commons DbUtils.closeQuietly().

Spowoduje to zamknięcie kombinacji ResultSets, Statements i Connections, obsługujących wartości zerowe po drodze. Nie będzie obsługiwać wielu notatek ResultSets, ale przydaje się inaczej.

Powiązane problemy