Как уже говорили другие, ваш код в основном правильный, хотя внешний try
не нужен. Вот еще несколько мыслей.
DataSource
Другие ответы здесь правильные и хорошие, такие как принятый Ответ от bpgergo. Но ни один из них не демонстрирует использование DataSource
, обычно рекомендуемое по сравнению с использованием DriverManager
в современной Java.
Итак, ради полноты, вот полный пример, который выбирает текущую дату с сервера базы данных. Используемая здесь база данных - Postgres . Любая другая база данных будет работать аналогично. Вы бы заменили использование org.postgresql.ds.PGSimpleDataSource
с реализациейDataSource
соответствующую вашей базе данных. Реализация, вероятно, обеспечивается вашим конкретным драйвером или пулом соединений, если вы идете по этому пути.
DataSource
Реализации нужны не быть закрыты, потому что она никогда не «открыто». A DataSource
не является ресурсом, не подключен к базе данных, поэтому он не содержит сетевых подключений и ресурсов на сервере базы данных. A DataSource
- это просто информация, необходимая при установлении соединения с базой данных, с сетевым именем или адресом сервера базы данных, именем пользователя, паролем пользователя и различными параметрами, которые вы хотите указать, когда соединение в конце концов устанавливается. Таким образом, ваш DataSource
объект реализации не входит в скобки try-with-resources.
Вложенная попытка с ресурсами
Ваш код правильно использует вложенные операторы try-with-resources.
Обратите внимание, что в приведенном ниже примере кода мы также используем синтаксис try-with-resources дважды , один вложен в другой. Внешний try
определяет два ресурса: Connection
и PreparedStatement
. Внутреннее try
определяет ResultSet
ресурс. Это общая структура кода.
Если исключение выдается из внутреннего и не перехватывается там, ResultSet
ресурс автоматически закрывается (если он существует, не ноль). После этого PreparedStatement
будет закрыто, и, наконец, Connection
закрыто. Ресурсы автоматически закрываются в обратном порядке, в котором они были объявлены в инструкциях try-with-resource.
Пример кода здесь слишком упрощен. Как написано, это может быть выполнено с одним оператором try-with-resources. Но в реальной работе вы, вероятно, будете выполнять больше работы между вложенными парами try
вызовов. Например, вы можете извлекать значения из вашего пользовательского интерфейса или POJO, а затем передавать их для выполнения ?
заполнителей в вашем SQL через вызовыPreparedStatement::set…
методов.
Синтаксические заметки
Точка с запятой
Обратите внимание, что точка с запятой, завершающая последний оператор ресурса в скобках try-with-resources, является необязательной. Я включил его в свою собственную работу по двум причинам: согласованность, и она выглядит завершенной, и это облегчает вставку копий в сочетание строк, не беспокоясь о точках с запятой в конце строки. Ваша IDE может пометить последнюю точку с запятой как лишнюю, но не оставляя вреда.
Java 9 - использовать существующие переменные в try-with-resources
Новое в Java 9 - это улучшение синтаксиса проб с ресурсами. Теперь мы можем объявить и заполнить ресурсы за пределами скобок try
оператора. Я еще не нашел это полезным для ресурсов JDBC, но помните об этом в своей собственной работе.
ResultSet
должен закрыть себя, но не может
В идеальном мире ResultSet
он закрывается, как обещает документация:
Объект ResultSet автоматически закрывается, когда объект Statement, который его сгенерировал, закрывается, выполняется повторно или используется для получения следующего результата из последовательности нескольких результатов.
К сожалению, в прошлом некоторые драйверы JDBC печально не выполняли это обещание. В результате, многие программисты JDBC научились явно закрыть все свои ресурсы , включая JDBC Connection
, PreparedStatement
и ResultSet
тоже. Современный синтаксис try-with-resources сделал это проще и с более компактным кодом. Обратите внимание, что команда Java пошла на то, чтобы пометить ResultSet
какAutoCloseable
, и я предлагаю использовать это. Использование try-with-resources во всех ваших ресурсах JDBC делает ваш код более самодокументируемым в соответствии с вашими намерениями.
Пример кода
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()) {
потому что объект ResultSet автоматически закрывается объектом Statement, который его сгенерировал