Menutup Koneksi Database di Java

121

Saya sedikit bingung, saya membaca di bawah ini dari http://en.wikipedia.org/wiki/Java_Database_Connectivity

Connection conn = DriverManager.getConnection(
     "jdbc:somejdbcvendor:other data needed by some jdbc vendor",
     "myLogin",
     "myPassword" );

Statement stmt = conn.createStatement();
try {
    stmt.executeUpdate( "INSERT INTO MyTable( name ) VALUES ( 'my name' ) " );
} finally {
    //It's important to close the statement when you are done with it
    stmt.close();
}

Apakah Anda tidak perlu menutup koneksi conn? Apa yang sebenarnya terjadi jika conn.close () tidak muncul?

Saya memiliki aplikasi web pribadi yang saya pertahankan yang saat ini tidak menutup salah satu formulir, tetapi apakah yang penting benar-benar adalah pengelola, yang terhubung, atau keduanya?

Situs ini terus turun sesekali tetapi server terus mengatakan itu adalah masalah koneksi database, kecurigaan saya adalah itu tidak ditutup, tetapi saya tidak tahu mana yang harus ditutup.

onaclov2000
sumber
Itu selalu merupakan praktik terbaik untuk menutup koneksi Anda sendiri, tanpa bergantung pada driver dan templat lain untuk menangani penutupan. Kegagalan menutup koneksi akan mengakibatkan soket dan sumber daya terbuka selamanya hingga terjadi crash (tidak ada lagi skenario sumber daya) atau restart.
Arun Joshla

Jawaban:

196

Ketika Anda selesai menggunakan milik Anda Connection, Anda perlu menutupnya secara eksplisit dengan memanggil close()metodenya untuk melepaskan sumber daya database lain (kursor, pegangan, dll) yang mungkin dipegang oleh koneksi.

Sebenarnya, pola aman di Java adalah menutup Anda ResultSet,, Statementdan Connection(dalam urutan itu) di finallyblok ketika Anda selesai dengannya, sesuatu seperti itu:

Connection conn = null;
PreparedStatement ps = null;
ResultSet rs = null;

try {
    // Do stuff
    ...

} catch (SQLException ex) {
    // Exception handling stuff
    ...
} finally {
    if (rs != null) {
        try {
            rs.close();
        } catch (SQLException e) { /* ignored */}
    }
    if (ps != null) {
        try {
            ps.close();
        } catch (SQLException e) { /* ignored */}
    }
    if (conn != null) {
        try {
            conn.close();
        } catch (SQLException e) { /* ignored */}
    }
}

The finallyblok dapat sedikit meningkat menjadi (untuk menghindari cek null):

} finally {
    try { rs.close(); } catch (Exception e) { /* ignored */ }
    try { ps.close(); } catch (Exception e) { /* ignored */ }
    try { conn.close(); } catch (Exception e) { /* ignored */ }
}

Tapi, tetap saja, ini sangat bertele-tele sehingga Anda biasanya berakhir menggunakan kelas helper untuk menutup objek dalam metode helper yang aman-null dan finallybloknya menjadi seperti itu:

} finally {
    DbUtils.closeQuietly(rs);
    DbUtils.closeQuietly(ps);
    DbUtils.closeQuietly(conn);
}

Dan, sebenarnya, Apache Commons DbUtils memiliki DbUtilskelas yang melakukan itu sehingga tidak perlu menulis milik Anda sendiri.

Pascal Thivent
sumber
3
Bantuan yang luar biasa, terima kasih! Saya tidak menangkap atau berpikir tentang pernyataan conn! = Null.
onaclov2000
1
@ onaclov2000 Ya, rs, ps, connmungkin nulltergantung di mana istirahat kode. Itulah mengapa ini dikenal sebagai pola "aman".
Pascal Thivent
12
@Pascal Thivent: Sebenarnya kami tidak perlu menutup semuanya. Buku "Core Java Volume dua - Fitur Lanjutan" telah menulis: closeMetode Statementobjek secara otomatis menutup yang terkait ResultSetjika pernyataan tersebut memiliki set hasil terbuka. Demikian pula, closemetode dari Connectionkelas menutup semua Statementsdari Connection.
Majid Azimi
12
@ Majid: Kecuali jika itu adalah koneksi yang dikumpulkan. Pernyataan itu kemudian akan bocor.
BalusC
1
@BalusC: Bisakah Anda menjelaskan apa yang terjadi ketika koneksi gabungan ditutup dengan menggunakan metode koneksi.close ()
Krsna Chaitanya
61

Itu selalu lebih baik untuk menutup objek database / sumber daya setelah digunakan. Lebih baik menutup koneksi, resultet dan objek pernyataan di finallyblok.

Hingga Java7, semua sumber daya ini harus ditutup menggunakan finallyblok. Jika Anda menggunakan Java 7, maka untuk menutup sumber daya Anda dapat melakukan hal berikut.

try(Connection con = getConnection(url, username, password, "org.postgresql.Driver");
    Statement stmt = con.createStatement();
    ResultSet rs = stmt.executeQuery(sql);
) {

//statements
}catch(....){}

Sekarang, objek con, stmt dan rs menjadi bagian dari blok percobaan dan java secara otomatis menutup sumber daya ini setelah digunakan.

Semoga saya bisa membantu.

Yadu Krishnan
sumber
Bagaimana jika pernyataan saya implisit, yaitu ResultSet rs = conn.createStatement().executeQuery(sql);di dalam tryblok?
Antares42
1
Anda tidak akan bisa mereferensikan mereka di blok {} terakhir untuk penutupan. Jika pengecualian dilemparkan, metode close () dari ResultSet tidak akan pernah dipanggil
Dan
Apa yang terjadi jika saya tidak menutupnya?
Alex78191
jika Anda tidak menutupnya, kebocoran memori dapat terjadi.
Yadu Krishnan
14

Cukup menutup saja Statementdan Connection. Tidak perlu menutup ResultSetobjek secara eksplisit .

Dokumentasi Java mengatakan tentang java.sql.ResultSet:

Objek ResultSet secara otomatis ditutup oleh objek Pernyataan yang dihasilkan ketika objek Pernyataan ditutup, dieksekusi ulang, atau digunakan untuk mengambil hasil berikutnya dari urutan beberapa hasil.


Terima kasih BalusC atas komentarnya: "Saya tidak akan mengandalkan itu. Beberapa driver JDBC gagal melakukannya."

Grigori A.
sumber
25
Saya tidak akan mengandalkan itu. Beberapa driver JDBC gagal melakukannya. Misalnya Oracle dengan "Kursor terbuka maksimum terlampaui", dll. Tutup saja semua sumber daya yang terbuka secara eksplisit, tanpa alasan.
BalusC
1
Saya lebih suka tidak menggunakan driver yang tidak sesuai dengan spesifikasi
Enerccio
2
Seperti yang ditunjukkan BalusC, adalah pemrograman defensif yang baik untuk menutup koneksi secara eksplisit daripada memasang ketergantungan pada penyedia tertentu.
michaelok
11

Iya. Anda perlu menutup kumpulan hasil, pernyataan, dan koneksi. Jika koneksi datang dari sebuah pool, menutupnya sebenarnya akan mengirimnya kembali ke pool untuk digunakan kembali.

Anda biasanya harus melakukan ini dalam satu finally{}blok, sehingga jika ada pengecualian, Anda masih mendapat kesempatan untuk menutupnya.

Banyak kerangka kerja yang akan menangani masalah alokasi / pelepasan alokasi sumber daya ini untuk Anda. misalnya JdbcTemplate Spring . Apache DbUtils memiliki metode untuk menjaga penutupan hasil / pernyataan / koneksi apakah null atau tidak (dan menangkap pengecualian saat menutup), yang juga dapat membantu.

Brian Agnew
sumber
1
Saat saya menyisipkan gerhana "akhirnya" suka menyorotinya, memberi tahu saya bahwa itu salah. haruskah ini pergi setelah blok tangkapan?
onaclov2000
Iya. coba {} tangkap {} akhirnya {}. Tangkapan {} adalah opsional, btw. Sama seperti akhirnya {}
Brian Agnew
Saya memindahkan pernyataan "tutup" ke bagian akhirnya, tetapi mereka hanya mengatakan "sqlexception", ada saran?
onaclov2000
1
close () melontarkan SQLException. Anda harus mengatasinya. Lihat DbUtils.closeQuietly () untuk menangani ini secara diam-diam.
Brian Agnew
> Apa yang sebenarnya terjadi jika conn.close () tidak muncul?
Alex78191
8

Sebenarnya, yang terbaik adalah jika Anda menggunakan blok try-with-resources dan Java akan menutup semua koneksi untuk Anda saat Anda keluar dari blok try.

Anda harus melakukan ini dengan objek apa pun yang mengimplementasikan AutoClosable.

try (Connection connection = getDatabaseConnection(); Statement statement = connection.createStatement()) {
    String sqlToExecute = "SELECT * FROM persons";
    try (ResultSet resultSet = statement.execute(sqlToExecute)) {
        if (resultSet.next()) {
            System.out.println(resultSet.getString("name");
        }
    }
} catch (SQLException e) {
    System.out.println("Failed to select persons.");
}

Panggilan ke getDatabaseConnection baru saja dibuat. Gantilah dengan panggilan yang memberi Anda koneksi SQL JDBC atau koneksi dari pool.

Joe
sumber
Jadi Anda tidak harus menutup koneksi secara manual dalam kasus ini?
Colin D
1
Benar. Anda tidak harus menutup koneksi secara eksplisit. Ini akan ditutup ketika akhir dari blok kode percobaan tercapai.
Joe
7

Ya, Anda harus menutup Koneksi. Jika tidak, klien database biasanya akan menjaga koneksi soket dan sumber daya lainnya tetap terbuka.

Alex Miller
sumber
... sampai keluar. Ini mengikat berbagai sumber daya terbatas di sisi klien dan server. Jika klien melakukan hal semacam ini terlalu banyak, hal itu dapat menyebabkan masalah bagi klien itu sendiri, layanan database, dan bahkan mungkin untuk aplikasi lain yang berjalan pada mesin klien atau server.
Stephen C