Jak powiedzieli inni, twój kod jest w zasadzie poprawny, chociaż zewnętrzna część tryjest 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, DriverManagerwe 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.PGSimpleDataSourceimplementacją DataSourceodpowiedniej dla Twojej bazy danych. Implementacja jest prawdopodobnie dostarczana przez określony sterownik lub pulę połączeń, jeśli wybierzesz tę trasę.
DataSourceRealizacja musi nie być zamknięte, ponieważ nigdy nie jest „otwarty”. A DataSourcenie jest zasobem, nie jest połączony z bazą danych, więc nie utrzymuje połączeń sieciowych ani zasobów na serwerze bazy danych. A DataSourceto 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 DataSourceobiekt 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 trydefiniuje dwa zasoby: Connectioni PreparedStatement. Wewnętrzna tryokreśla ResultSetzasób. To jest wspólna struktura kodu.
Jeśli wyjątek zostanie wyrzucony z wewnętrznego i nie zostanie tam przechwycony, ResultSetzasób zostanie automatycznie zamknięty (jeśli istnieje, nie jest zerowy). Następnie PreparedStatementzostanie zamknięty, a na koniec Connectionzamknię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 trywywoł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 tryinstrukcji. 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 ResultSetzamknęł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, PreparedStatementi ResultSetteż. Nowoczesna składnia try-with-resources sprawiła, że jest to łatwiejsze i bardziej kompaktowe. Zauważ, że zespół Java zajął się oznaczaniem ResultSetjako AutoCloseablei 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