Saya punya metode untuk mendapatkan pengguna dari database dengan JDBC:
public List<User> getUser(int userId) {
String sql = "SELECT id, name FROM users WHERE id = ?";
List<User> users = new ArrayList<User>();
try {
Connection con = DriverManager.getConnection(myConnectionURL);
PreparedStatement ps = con.prepareStatement(sql);
ps.setInt(1, userId);
ResultSet rs = ps.executeQuery();
while(rs.next()) {
users.add(new User(rs.getInt("id"), rs.getString("name")));
}
rs.close();
ps.close();
con.close();
} catch (SQLException e) {
e.printStackTrace();
}
return users;
}
Bagaimana saya harus menggunakan Java 7 coba-dengan-sumber daya untuk meningkatkan kode ini?
Saya telah mencoba dengan kode di bawah ini, tetapi menggunakan banyak try
blok, dan tidak banyak meningkatkan keterbacaan . Haruskah saya menggunakan try-with-resources
cara lain?
public List<User> getUser(int userId) {
String sql = "SELECT id, name FROM users WHERE id = ?";
List<User> users = new ArrayList<>();
try {
try (Connection con = DriverManager.getConnection(myConnectionURL);
PreparedStatement ps = con.prepareStatement(sql);) {
ps.setInt(1, userId);
try (ResultSet rs = ps.executeQuery();) {
while(rs.next()) {
users.add(new User(rs.getInt("id"), rs.getString("name")));
}
}
}
} catch (SQLException e) {
e.printStackTrace();
}
return users;
}
java
jdbc
java-7
try-with-resources
Jonas
sumber
sumber
try (ResultSet rs = ps.executeQuery()) {
karena objek ResultSet secara otomatis ditutup oleh objek Pernyataan yang menghasilkannyaConnection
,PreparedStatement
danResultSet
juga. Tidak ada alasan untuk tidak melakukannya, karena coba-dengan-sumber daya membuatnya sangat mudah dan membuat kode kita lebih mendokumentasikan diri sendiri tentang niat kita.Jawaban:
Tidak perlu untuk percobaan luar dalam contoh Anda, jadi Anda setidaknya bisa turun dari 3 ke 2, dan Anda juga tidak perlu menutup
;
pada akhir daftar sumber daya. Keuntungan menggunakan dua blok percobaan adalah bahwa semua kode Anda ada di depan sehingga Anda tidak perlu merujuk ke metode terpisah:sumber
Connection::setAutoCommit
? Panggilan seperti itu tidak diizinkan ditry
antaracon =
danps =
. Saat mendapatkan Koneksi dari DataSource yang mungkin didukung dengan kumpulan koneksi, kami tidak dapat berasumsi bagaimana autoCommit diatur.DriverManager.getConnection(myConnectionURL)
ke metode yang juga menetapkan flag autoCommit dan mengembalikan koneksi (atau mengaturnya dengancreatePreparedStatement
metode yang sama dalam contoh sebelumnya ...)DataSource
managetConnection
metode melakukan seperti yang Anda katakan, dapatkan koneksi dan konfigurasikan sesuai kebutuhan, kemudian meneruskan koneksi.Saya menyadari ini sudah lama dijawab tetapi ingin menyarankan pendekatan tambahan yang menghindari blok ganda coba-dengan-sumber daya bersarang.
sumber
createPreparedStatement
tidak aman terlepas dari bagaimana Anda menggunakannya. Untuk memperbaikinya Anda harus menambahkan try-catch di sekitar setInt (...), menangkap apa sajaSQLException
, dan ketika itu terjadi panggilan ps.close () dan rethrow pengecualian. Tetapi itu akan menghasilkan kode yang hampir sepanjang dan tidak memenuhi syarat seperti yang ingin ditingkatkan oleh OP.Berikut adalah cara ringkas menggunakan lambdas dan Pemasok JDK 8 agar sesuai dengan semua yang ada di luar coba:
sumber
Bagaimana dengan membuat kelas pembungkus tambahan?
Kemudian di kelas panggilan Anda dapat menerapkan metode prepStatement sebagai:
sumber
Seperti yang telah dinyatakan orang lain, kode Anda pada dasarnya benar meskipun bagian luar
try
tidak diperlukan. Ini beberapa pemikiran lagi.DataSource
Jawaban lain di sini benar dan bagus, seperti yang diterima oleh bpgergo. Tapi tidak ada yang menunjukkan penggunaan
DataSource
, lebih sering direkomendasikan daripada penggunaanDriverManager
di Jawa modern.Jadi demi kelengkapan, berikut adalah contoh lengkap yang mengambil tanggal saat ini dari server database. Basis data yang digunakan di sini adalah Postgres . Basis data lain mana pun akan bekerja dengan cara yang sama. Anda akan mengganti penggunaan
org.postgresql.ds.PGSimpleDataSource
dengan implementasi yangDataSource
sesuai dengan database Anda. Suatu implementasi kemungkinan disediakan oleh pengemudi khusus Anda, atau kumpulan koneksi jika Anda pergi rute itu.Sebuah
DataSource
implementasi perlu tidak ditutup, karena tidak pernah “dibuka”. ADataSource
bukan sumber daya, tidak terhubung ke database, jadi ia tidak memegang koneksi jaringan atau sumber daya pada server database. ADataSource
hanyalah informasi yang diperlukan ketika membuat koneksi ke database, dengan nama atau alamat jaringan server database, nama pengguna, kata sandi pengguna, dan berbagai opsi yang ingin Anda tentukan ketika suatu koneksi akhirnya dibuat. JadiDataSource
objek implementasi Anda tidak masuk ke dalam tanda kurung coba-dengan-sumber daya Anda.Bersarang coba-dengan-sumber daya
Kode Anda digunakan dengan benar untuk pernyataan try-with-resources bersarang.
Perhatikan pada contoh kode di bawah ini bahwa kami juga menggunakan sintaks coba sumber daya dua kali , satu bersarang di dalam yang lain. Bagian luar
try
mendefinisikan dua sumber daya:Connection
danPreparedStatement
. Batintry
mendefinisikanResultSet
sumber daya. Ini adalah struktur kode yang umum.Jika pengecualian dilemparkan dari dalam, dan tidak ditangkap di sana,
ResultSet
sumber daya akan secara otomatis ditutup (jika ada, bukan nol). Setelah itu,PreparedStatement
akan ditutup, dan terakhirConnection
ditutup. Sumber daya secara otomatis ditutup dalam urutan terbalik yang dinyatakan dalam pernyataan coba-dengan-sumber daya.Contoh kode di sini terlalu sederhana. Seperti yang tertulis, itu dapat dieksekusi dengan pernyataan coba-dengan-sumber daya tunggal. Tetapi dalam pekerjaan nyata Anda mungkin akan melakukan lebih banyak pekerjaan di antara pasangan
try
panggilan yang bersarang . Misalnya, Anda mungkin mengekstraksi nilai dari antarmuka pengguna atau POJO, dan kemudian meneruskannya untuk memenuhi?
placeholder dalam SQL Anda melalui panggilan kePreparedStatement::set…
metode.Catatan sintaks
Mengejar titik koma
Perhatikan bahwa koma yang membuntuti pernyataan sumber daya terakhir dalam tanda kurung sumber daya percobaan adalah opsional. Saya memasukkannya ke dalam karya saya sendiri karena dua alasan: Konsistensi dan kelihatannya lengkap, dan itu membuat copy-paste campuran garis lebih mudah tanpa harus khawatir tentang titik koma akhir-line. IDE Anda mungkin menandai titik koma terakhir sebagai berlebihan, tetapi tidak ada salahnya meninggalkannya.
Java 9 - Gunakan vars yang ada di try-with-resources
Baru di Java 9 adalah penyempurnaan dari sintaks coba sumber daya. Kami sekarang dapat mendeklarasikan dan mengisi sumber daya di luar tanda kurung
try
pernyataan. Saya belum menemukan ini berguna untuk sumber daya JDBC, tetapi perlu diingat dalam pekerjaan Anda sendiri.ResultSet
harus menutup sendiri, tetapi mungkin tidakDalam dunia yang ideal itu
ResultSet
akan menutup sendiri sesuai dengan yang dijanjikan dokumentasi:Sayangnya, di masa lalu beberapa driver JDBC terkenal gagal memenuhi janji ini. Akibatnya, banyak programmer JDBC belajar untuk secara eksplisit menutup semua sumber daya JDBC mereka termasuk
Connection
,PreparedStatement
danResultSet
juga. Sintaks coba-dengan-sumber daya modern telah membuatnya menjadi lebih mudah, dan dengan kode yang lebih ringkas. Perhatikan bahwa tim Java bersusah payah menandaiResultSet
sebagaiAutoCloseable
, dan saya sarankan kita memanfaatkannya. Menggunakan coba-dengan-sumber daya di sekitar semua sumber daya JDBC Anda membuat kode Anda lebih mendokumentasikan diri sendiri tentang niat Anda.Contoh kode
sumber