Uważa się, że dobrym nawykiem jest zamykanie wszystkich zasobów JDBC po użyciu. Ale jeśli mam następujący kod, czy konieczne jest zamknięcie zestawu wyników i instrukcji?
Connection conn = null;
PreparedStatement stmt = null;
ResultSet rs = null;
try {
conn = // Retrieve connection
stmt = conn.prepareStatement(// Some SQL);
rs = stmt.executeQuery();
} catch(Exception e) {
// Error Handling
} finally {
try { if (rs != null) rs.close(); } catch (Exception e) {};
try { if (stmt != null) stmt.close(); } catch (Exception e) {};
try { if (conn != null) conn.close(); } catch (Exception e) {};
}
Pytanie brzmi, czy zamknięcie połączenia wykonuje zadanie, czy też pozostawia niektóre zasoby w użyciu.
Odpowiedzi:
To, co zrobiłeś, to doskonała i bardzo dobra praktyka.
Powodem, dla którego mówię, że jest to dobra praktyka ... Na przykład, jeśli z jakiegoś powodu używasz „prymitywnego” typu puli bazy danych i wywołujesz połączenie
connection.close()
, połączenie zostanie zwrócone do puli iResultSet
/Statement
nigdy nie zostanie zamknięte, a następnie napotka wiele różnych nowych problemów!Więc nie zawsze możesz liczyć na
connection.close()
sprzątanie.Mam nadzieję, że to pomoże :)
źródło
Java 1.7 znacznie ułatwia nam życie dzięki instrukcji try-with-resources .
Ta składnia jest dość krótka i elegancka. I
connection
rzeczywiście będzie zamknięty, nawet jeślistatement
nie da się go stworzyć.źródło
;
)Z javadocs :
Jednak javadocs nie są bardzo jasne, czy
Statement
iResultSet
są zamykane po zamknięciu instrumentu bazowegoConnection
. Po prostu stwierdzają, że zamknięcie połączenia:Moim zdaniem, zawsze jawnie zamknij
ResultSets
,Statements
aConnections
kiedy skończysz z nimi, ponieważ implementacjaclose
może się różnić w zależności od sterowników bazy danych.Możesz zaoszczędzić sobie dużo kodu płyty kotłowej, stosując metody takie jak
closeQuietly
w DBUtils firmy Apache.źródło
Teraz używam Oracle z Javą. Oto mój punkt widzenia:
Powinieneś zamknąć
ResultSet
iStatement
wyraźnie, ponieważ Oracle ma problemy z utrzymaniem otwartych kursorów nawet po zamknięciu połączenia. Jeśli nie zamknieszResultSet
(kursora), pojawi się błąd, taki jak przekroczenie maksymalnej liczby otwartych kursorów .Myślę, że możesz napotkać ten sam problem z innymi bazami danych, z których korzystasz.
Oto samouczek Zamknij zestaw wyników po zakończeniu :
źródło
Jeśli chcesz mieć bardziej zwarty kod, sugeruję użycie Apache Commons DbUtils . W tym przypadku:
źródło
Ta poprawna i bezpieczna metoda zamknięcia zasobów powiązanych z JDBC to (zaczerpnięta z Jak poprawnie zamknąć zasoby JDBC - za każdym razem ):
źródło
Nie ma znaczenia, czy
Connection
można je gromadzić czy nie. Nawet połączenie z pulą musi zostać wyczyszczone przed powrotem do basenu.„Wyczyść” zwykle oznacza zamknięcie zestawów wyników i wycofanie wszelkich oczekujących transakcji, ale nie zamknięcie połączenia. W przeciwnym razie pula traci sens.
źródło
Nie, nie musisz niczego zamykać, ALE połączenie. Zgodnie ze specyfikacją JDBC zamknięcie dowolnego wyższego obiektu spowoduje automatyczne zamknięcie niższych obiektów. Zamknięcie
Connection
spowoduje zamknięcie wszystkichStatement
utworzonych połączeń. Zamknięcie dowolnegoStatement
spowoduje zamknięcie wszystkich,ResultSet
które zostały utworzone przez toStatement
. Nie ma znaczenia, czyConnection
można je gromadzić czy nie. Nawet połączenie z pulą musi zostać wyczyszczone przed powrotem do basenu.Oczywiście możesz mieć długie zagnieżdżone pętle na
Connection
tworzeniu wielu instrukcji, a następnie zamknięcie ich jest właściwe. Prawie nigdy nie zamykamResultSet
, wydaje się przesadny podczas zamykaniaStatement
lubConnection
BĘDZIE je zamykać.źródło
Stworzyłem następującą metodę tworzenia One Liner wielokrotnego użytku:
Używam tego kodu w klasie nadrzędnej odziedziczonej po wszystkich moich klasach, które wysyłają zapytania DB. Mogę używać Oneliner na wszystkich zapytaniach, nawet jeśli nie mam wynikowego zestawu. Metoda zajmuje się zamykaniem zestawu wyników, instrukcji, połączenia we właściwej kolejności. Tak wygląda mój wreszcie blok.
źródło
O ile pamiętam, w obecnym JDBC zestawy wyników i instrukcje implementują interfejs AutoCloseable. Oznacza to, że są one zamykane automatycznie po ich zniszczeniu lub przekroczeniu zakresu.
źródło
close
wywoływana jest na końcu instrukcji try-with-resources. Zobacz docs.oracle.com/javase/tutorial/essential/exceptions/... i docs.oracle.com/javase/8/docs/api/java/lang/AutoCloseable.html .Niektóre funkcje wygody:
źródło
W przypadku formularza Java 6 lepiej jest sprawdzić, czy jest zamknięty, czy nie przed zamknięciem (na przykład, jeśli jakiś puli połączeń wyklucza połączenie w innym wątku) - na przykład jakiś problem z siecią - stan instrukcji i zestawu wyników można zamknąć. (nie zdarza się to często, ale miałem ten problem z Oracle i DBCP). Mój wzór jest taki (w starszej składni Java) to:
Teoretycznie nie jest w 100% idealny, ponieważ między sprawdzaniem stanu zamknięcia a samym zamknięciem jest trochę miejsca na zmianę stanu. W najgorszym przypadku dostaniesz ostrzeżenie na długo. - ale jest mniejsza niż możliwość zmiany stanu w zapytaniach długoterminowych. Używamy tego wzorca w produkcji z obciążeniem „przeciętnym” (150 jednoczesnych użytkowników) i nie mieliśmy z nim problemu - więc nigdy nie wyświetlaj tego komunikatu ostrzegawczego.
źródło
isClosed()
Testy nie są potrzebne , ponieważ zamknięcie któregokolwiek z nich, które jest już zamknięte, nie jest możliwe. Co eliminuje problem okna czasowego. Który zostałby również wyeliminowany poprzez utworzenie zmiennych lokalnychConnection, Statement
iResultSet
.