Як зазначають інші, ваш код в основному правильний, хоча зовнішній try
вигляд непотрібний. Ось ще кілька думок.
DataSource
Інші відповіді тут правильні і хороші, такий прийнятий Відповідь від bpgergo. Але жоден з них не показує використання DataSource
, як правило, рекомендується над використанням DriverManager
сучасних Java.
Отже, для повноти, ось повний приклад, який отримує поточну дату з сервера баз даних. Тут використовується база даних Postgres . Будь-яка інша база даних буде працювати аналогічно. Ви б замінили використання org.postgresql.ds.PGSimpleDataSource
на реалізацію, DataSource
відповідну вашій базі даних. Реалізація, ймовірно, надається вашим конкретним драйвером або пулом з'єднань, якщо ви йдете цим маршрутом.
DataSource
Реалізації потрібні НЕ бути закриті, тому що вона ніколи не «відкрито». A DataSource
не є ресурсом, не підключений до бази даних, тому він не містить мережевих з'єднань, ані ресурсів на сервері баз даних. A DataSource
- це просто інформація, необхідна під час встановлення з'єднання з базою даних, з мережевим іменем або адресою сервера бази даних, ім'ям користувача, паролем користувача та різними параметрами, які ви хочете вказати, коли з часом встановлено з'єднання. Таким чином, DataSource
об’єкт реалізації не заходить у ваші круглі дужки пробних ресурсів.
Вкладені пробні ресурси
Ваш код належним чином використовує вкладені заяви про тестування ресурсів.
Зауважте в наведеному нижче прикладі коду, що ми також двічі використовуємо синтаксис спробу використання ресурсів , один вкладений всередині іншого. Зовнішній try
визначає два ресурси: Connection
і PreparedStatement
. Внутрішня try
визначає ResultSet
ресурс. Це загальна структура коду.
Якщо виняток буде викинуто з внутрішнього і не потрапив туди, ResultSet
ресурс автоматично закриється (якщо він існує, не є нульовим). Після цього PreparedStatement
заповіт буде закритий, і нарешті Connection
, закритий. Ресурси автоматично закриваються в зворотному порядку, в якому вони були задекларовані в операторах спробування ресурсів.
Приклад коду тут надмірно спрощений. Як написано, це може бути виконано за допомогою одного оператора "спробу використання ресурсів". Але в реальній роботі ви, ймовірно, будете робити більше роботи між вкладеною парою try
дзвінків. Наприклад, ви можете витягувати значення з інтерфейсу користувача або POJO, а потім передавати їх на виконання ?
заповнювачів у вашому SQL за допомогою викликів PreparedStatement::set…
методів.
Синтаксичні нотатки
Зворотна крапка з комою
Зауважте, що крапка з комою, що відкладає останню заяву про ресурси, в дужках спробувати-ресурси - необов’язкова. Я включаю його до своєї роботи з двох причин: Послідовність і вона виглядає повноцінною, і це полегшує копіювання суміші рядків легше, не турбуючись про крапки з комою крапки. Ваш IDE може позначити останню крапку з комою як зайву, але немає шкоди, залишаючи її.
Java 9 - Використовуйте наявні VARS у спробах використання ресурсів
Нове в Java 9 - це вдосконалення синтаксису "пробних ресурсів". Тепер ми можемо оголошувати та заповнювати ресурси поза дужками try
заяви. Я ще не знайшов цього корисного для ресурсів JDBC, але пам’ятайте про це у власній роботі.
ResultSet
повинен закрити себе, а може і не
В ідеальному світі це ResultSet
закриється, як обіцяє документація:
Об'єкт ResultSet автоматично закривається, коли об'єкт заяви, який його створив, закривається, повторно виконується або використовується для отримання наступного результату з послідовності декількох результатів.
На жаль, у минулому деякі водії JDBC ганебно не виконали цієї обіцянки. В результаті, багато програмістів JDBC навчилися явно закрити всі свої ресурси , включаючи JDBC Connection
, PreparedStatement
і ResultSet
теж. Сучасний синтаксис "пробних ресурсів" зробив це простіше і з більш компактним кодом. Зауважте, що команда Java набридла відзначати ResultSet
як AutoCloseable
, і я пропоную скористатися цим. Використання пробних ресурсів навколо всіх ваших ресурсів 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, який його генерував