Menutup Koneksi JDBC di Pool

109

Bagian kode standar kami untuk menggunakan JDBC adalah ...

Connection conn = getConnection(...);
Statement  stmt = conn.conn.createStatement (ResultSet.TYPE_SCROLL_INSENSITIVE,
                                                ResultSet.CONCUR_READ_ONLY);
ResultSet  rset = stmt.executeQuery (sqlQuery);

// do stuff with rset

rset.close(); stmt.close(); conn.close();

Pertanyaan 1: Saat menggunakan Connection Pool, haruskah seseorang menutup Connection di bagian akhir? Jika ya, bukankah tujuan pengumpulan hilang? Dan jika tidak, bagaimana DataSource mengetahui kapan instance tertentu dari Connection dibebaskan dan dapat digunakan kembali? Saya sedikit bingung tentang yang satu ini, ada petunjuk yang dihargai.

Pertanyaan 2: Apakah metode berikut mendekati standar? Sepertinya upaya untuk mendapatkan koneksi dari kumpulan, dan jika DataSource tidak dapat dibuat, gunakan DriverManager model lama. Kami bahkan tidak yakin bagian mana yang dieksekusi saat runtime. Mengulangi pertanyaan di atas, haruskah seseorang menutup Koneksi yang keluar dari metode seperti itu?

Terima kasih, - MS.

synchronized public Connection getConnection (boolean pooledConnection)
                                                        throws SQLException {
        if (pooledConnection) {
                if (ds == null) {
                        try {
                                Context envCtx = (Context)
                                        new InitialContext().lookup("java:comp/env");
                                ds = (DataSource) envCtx.lookup("jdbc/NamedInTomcat");
                                return ds.getConnection();
                        } catch (NamingException e) {
                                e.printStackTrace();
                }}
                return (ds == null) ? getConnection (false) : ds.getConnection();
        }
        return DriverManager.getConnection(
                "jdbc:mysql://"+ipaddy+":"+dbPort +"/" + dbName, uName, pWord);
}

Sunting: Saya pikir kita mendapatkan koneksi gabungan karena kita tidak melihat jejak tumpukan.

Manidip Sengupta
sumber

Jawaban:

121

Saat menggunakan Connection Pool, haruskah seseorang menutup Connection di bagian akhir? Jika ya, bukankah tujuan pengumpulan hilang? Dan jika tidak, bagaimana DataSource mengetahui kapan instance tertentu dari Connection dibebaskan dan dapat digunakan kembali? Saya sedikit bingung tentang yang satu ini, ada petunjuk yang dihargai.

Ya, tentu saja Anda juga perlu menutup koneksi gabungan. Ini sebenarnya pembungkus di sekitar koneksi yang sebenarnya. Itu akan di bawah selimut melepaskan koneksi yang sebenarnya kembali ke kolam. Lebih jauh ke kolam untuk memutuskan apakah koneksi sebenarnya akan benar - benar ditutup atau digunakan kembali untuk getConnection()panggilan baru . Jadi, terlepas dari apakah Anda menggunakan kumpulan koneksi atau tidak, Anda harus selalu menutup semua sumber daya JDBC dalam urutan terbalik di finallyblok tryblok tempat Anda memperolehnya. Di Java 7 ini dapat lebih disederhanakan dengan menggunakan try-with-resourcespernyataan.


Apakah metode berikut mendekati standar? Sepertinya upaya untuk mendapatkan koneksi dari kumpulan, dan jika DataSource tidak dapat dibuat, gunakan DriverManager model lama. Kami bahkan tidak yakin bagian mana yang dieksekusi saat runtime. Mengulangi pertanyaan di atas, haruskah seseorang menutup Koneksi yang keluar dari metode seperti itu?

Contohnya cukup menakutkan. Anda hanya perlu mencari / menginisialisasi DataSourcehanya sekali selama startup aplikasi di beberapa konstruktor / inisialisasi kelas konfigurasi DB di seluruh aplikasi. Kemudian panggil saja getConnection()satu sumber data yang sama selama sisa masa pakai aplikasi. Tidak perlu sinkronisasi atau pemeriksaan nihil.

Lihat juga:

BalusC
sumber
Itulah yang dilakukannya (diinisialisasi sekali), bukan? ds adalah variabel instan, dan jika (ds == null) ... adalah bagian inisialisasi.
Manidip Sengupta
Melakukan pemeriksaan setiap kali dengan metode get getConnection()itu aneh. Lakukan saja di blok c'tor atau inisialisasi dari kelas yang sama, tanpa sinkronisasi / pemeriksaan nihil. Ini akan dipanggil sekali. Untuk lebih banyak petunjuk dan contoh awal, Anda mungkin menemukan artikel ini berguna.
BalusC
Artikel yang sangat bagus, BalusC. Kelas yang saya tangani cukup banyak mengimplementasikan Lapisan Data, menggunakan DTO. Saya setuju dengan Anda, inisialisasi harus dalam konstruktor. Sekarang, kelas ini memiliki banyak metode, masing-masing dengan conn, stmt dan rset sebagai variabel lokal, koneksi berada dalam blok percobaan, dan akhirnya ada panggilan 1-baris csrClose (conn, stmt, rset), di mana semua 3 ditutup (dalam urutan terbalik). Sekarang, DTO yang Anda kembangkan dalam contoh adalah gambar cermin dari baris tabel DB. Kami memiliki kueri SQL kompleks dengan gabungan (dan klausa lainnya), apakah Anda memiliki artikel tentang cara mengembangkan DAO untuk hasil seperti itu?
Manidip Sengupta
2
@yat: Anda HARUS memanggil close()mereka semua di finallyblok dari blok yang sama trydengan tempat Anda memperoleh / membuatnya. Ini sepenuhnya terlepas dari apakah itu koneksi yang dikumpulkan atau tidak.
BalusC
1
@ iJava: kolam itu ditulis oleh seorang amatir yang sama sekali tidak tahu apa yang dia lakukan. Abaikan dan cari perpustakaan yang sebenarnya. Misalnya HikariCP.
BalusC
22

Pool biasanya mengembalikan Anda objek Connection yang dibungkus, di mana metode close () diganti, biasanya mengembalikan Connection ke pool. Memanggil close () tidak masalah dan mungkin masih diperlukan.

Metode close () mungkin akan terlihat seperti ini:

public void close() throws SQLException {
  pool.returnConnection(this);
}

Untuk pertanyaan kedua, Anda bisa menambahkan logger untuk menunjukkan apakah blok bawah pernah berjalan. Saya membayangkan meskipun Anda hanya ingin satu cara atau yang lain untuk konfigurasi koneksi database Anda. Kami hanya menggunakan kolam untuk akses database kami. Bagaimanapun juga, menutup koneksi akan sangat penting untuk mencegah kebocoran.

ejekan
sumber
Saya setuju, kami memiliki logger, dan itu bisa digunakan di sini juga. Saya perlu belajar sedikit tentang bagaimana Anda dapat membungkus sebuah Objek, mengganti metode close () -nya tetapi tetap mempertahankan nama kelas yang sama (Koneksi)
Manidip Sengupta
1
Calling close() is OK and probably still required., tidak memanggil tutup akan membocorkan sambungan, kecuali kumpulan menerapkan beberapa strategi pemulihan
svarog
0

Sebenarnya, pendekatan terbaik untuk manajemen koneksi adalah dengan tidak memasukkannya ke kode apa pun di mana pun.

Buat kelas SQLExecutor yang merupakan satu-satunya lokasi yang membuka dan menutup koneksi.

Seluruh aplikasi lainnya kemudian memompa pernyataan ke dalam pelaksana daripada mendapatkan koneksi dari kumpulan dan mengelola (atau salah mengaturnya) di semua tempat.

Anda dapat memiliki eksekutor sebanyak yang Anda inginkan, tetapi tidak seorang pun boleh menulis kode yang membuka dan menutup koneksi atas namanya sendiri.

Mudahnya, ini juga memungkinkan Anda mencatat semua SQL Anda dari satu set kode.

Rodney P. Barbati
sumber