Jak powiedzieli inni, twój kod jest w zasadzie poprawny, chociaż zewnętrzna część try
jest niepotrzebna. Oto kilka innych myśli.
DataSource
Inne odpowiedzi tutaj są poprawne i dobre, takie jak zaakceptowana odpowiedź bpgergo. Ale żaden z nich nie używa DataSource
, powszechnie zalecanego używania, DriverManager
we współczesnej Javie.
Tak więc, aby uzyskać kompletność, oto kompletny przykład, który pobiera bieżącą datę z serwera bazy danych. Użyta tutaj baza danych to Postgres . Każda inna baza danych działałaby podobnie. Zastąpiłbyś użycie org.postgresql.ds.PGSimpleDataSource
implementacją DataSource
odpowiedniej dla Twojej bazy danych. Implementacja jest prawdopodobnie dostarczana przez określony sterownik lub pulę połączeń, jeśli wybierzesz tę trasę.
DataSource
Realizacja musi nie być zamknięte, ponieważ nigdy nie jest „otwarty”. A DataSource
nie jest zasobem, nie jest połączony z bazą danych, więc nie utrzymuje połączeń sieciowych ani zasobów na serwerze bazy danych. A DataSource
to po prostu informacje potrzebne podczas nawiązywania połączenia z bazą danych, z nazwą lub adresem sieciowym serwera bazy danych, nazwą użytkownika, hasłem użytkownika i różnymi opcjami, które mają być określone po ostatecznym nawiązaniu połączenia. Tak więc DataSource
obiekt implementacji nie jest umieszczany w nawiasach próbnych z zasobami.
Zagnieżdżone try-with-resources
Twój kod prawidłowo wykorzystuje zagnieżdżone instrukcje try-with-resources.
Zauważ, że w poniższym przykładowym kodzie używamy również składni try-with-resources dwukrotnie , jedna zagnieżdżona w drugiej. Zewnętrzny try
definiuje dwa zasoby: Connection
i PreparedStatement
. Wewnętrzna try
określa ResultSet
zasób. To jest wspólna struktura kodu.
Jeśli wyjątek zostanie wyrzucony z wewnętrznego i nie zostanie tam przechwycony, ResultSet
zasób zostanie automatycznie zamknięty (jeśli istnieje, nie jest zerowy). Następnie PreparedStatement
zostanie zamknięty, a na koniec Connection
zamknięty. Zasoby są automatycznie zamykane w odwrotnej kolejności, w jakiej zostały zadeklarowane w instrukcjach try-with-resource.
Przykładowy kod jest zbyt uproszczony. Jak napisano, można to wykonać za pomocą jednej instrukcji try-with-resources. Ale w prawdziwej pracy prawdopodobnie wykonasz więcej pracy między zagnieżdżonymi parami try
wywołań. Na przykład możesz wyodrębniać wartości z interfejsu użytkownika lub POJO, a następnie przekazywać je w celu wypełnienia ?
symboli zastępczych w języku SQL za pośrednictwem wywołań PreparedStatement::set…
metod.
Uwagi dotyczące składni
Końcowy średnik
Zwróć uwagę, że średnik kończący ostatnią instrukcję zasobu w nawiasach próby z zasobami jest opcjonalny. Uwzględniam go w mojej pracy z dwóch powodów: spójności i wygląda na kompletny, a także ułatwia kopiowanie i wklejanie mieszanki linii bez martwienia się o średniki końca wiersza. Twoje IDE może oznaczyć ostatni średnik jako zbędny, ale nie ma nic złego w pozostawieniu go.
Java 9 - Użyj istniejących zmiennych w próbach z zasobami
Nowością w Javie 9 jest ulepszenie składni try-with-resources. Teraz możemy zadeklarować i wypełnić zasoby poza nawiasami w try
instrukcji. Nie znalazłem jeszcze tego przydatnego dla zasobów JDBC, ale miej to na uwadze w swojej własnej pracy.
ResultSet
powinien się zamknąć, ale nie może
W idealnym świecie ResultSet
zamknęłaby się, jak obiecuje dokumentacja:
Obiekt ResultSet jest automatycznie zamykany, gdy obiekt Statement, który go wygenerował, zostanie zamknięty, ponownie wykonany lub użyty do pobrania następnego wyniku z sekwencji wielu wyników.
Niestety, w przeszłości niektóre sterowniki JDBC niesławnie nie spełniały tej obietnicy. W rezultacie, wielu programistów JDBC nauczył się wyraźnie blisko wszystkich swoich zasobów JDBC tym Connection
, PreparedStatement
i ResultSet
też. Nowoczesna składnia try-with-resources sprawiła, że jest to łatwiejsze i bardziej kompaktowe. Zauważ, że zespół Java zajął się oznaczaniem ResultSet
jako AutoCloseable
i sugeruję, abyśmy to wykorzystali. Korzystanie z zasobów typu „try-with-resources” wokół wszystkich zasobów JDBC sprawia, że kod jest bardziej samodokumentujący, jeśli chodzi o intencje.
Przykład kodu
package work.basil.example;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.time.LocalDate;
import java.util.Objects;
public class App
{
public static void main ( String[] args )
{
App app = new App();
app.doIt();
}
private void doIt ( )
{
System.out.println( "Hello World!" );
org.postgresql.ds.PGSimpleDataSource dataSource = new org.postgresql.ds.PGSimpleDataSource();
dataSource.setServerName( "1.2.3.4" );
dataSource.setPortNumber( 5432 );
dataSource.setDatabaseName( "example_db_" );
dataSource.setUser( "scott" );
dataSource.setPassword( "tiger" );
dataSource.setApplicationName( "ExampleApp" );
System.out.println( "INFO - Attempting to connect to database: " );
if ( Objects.nonNull( dataSource ) )
{
String sql = "SELECT CURRENT_DATE ;";
try (
Connection conn = dataSource.getConnection() ;
PreparedStatement ps = conn.prepareStatement( sql ) ;
)
{
… make `PreparedStatement::set…` calls here.
try (
ResultSet rs = ps.executeQuery() ;
)
{
if ( rs.next() )
{
LocalDate ld = rs.getObject( 1 , LocalDate.class );
System.out.println( "INFO - date is " + ld );
}
}
}
catch ( SQLException e )
{
e.printStackTrace();
}
}
System.out.println( "INFO - all done." );
}
}
try (ResultSet rs = ps.executeQuery()) {
ponieważ obiekt ResultSet zostaje automatycznie zamknięty przez obiekt oświadczenie, że generowanego