Java'da Veritabanı Bağlantılarını Kapatma


121

Biraz kafam karıştı, http://en.wikipedia.org/wiki/Java_Database_Connectivity adresinden aşağıdakileri okuyordum

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();
}

Conn Bağlantısını kapatmanıza gerek yok mu? Conn.close () oluşmazsa gerçekten ne oluyor?

Bakımını yaptığım ve şu anda her iki formu da kapatmayan özel bir web uygulamam var, ancak önemli olan gerçekten stmt, conn olan veya her ikisi mi?

Site aralıklı olarak kapanmaya devam ediyor ancak sunucu bunun bir veritabanı bağlantısı sorunu olduğunu söylüyor, şüphem kapatılmaması, ancak hangisinin kapatılacağını bilmiyorum.


Kapanışla ilgili diğer sürücülere ve şablonlara bağlı kalmadan bağlantıları kendi başınıza kapatmak her zaman en iyi uygulamadır. Bağlantının kapatılmaması, soketlerin ve kaynakların bir çökmeye (artık kaynak senaryosu yok) veya yeniden başlatılmasına kadar sonsuza kadar açılmasına neden olur.
Arun Joshla

Yanıtlar:


196

Sizin kullanımınız bittiğinde , bağlantının bağlı olabileceği diğer veritabanı kaynaklarını (imleçler, tanıtıcılar, vb.) Serbest bırakmak Connectioniçin close()yöntemini çağırarak onu açıkça kapatmanız gerekir .

Aslında Java güvenli desen senin kapatmaktır ResultSet, Statementve Connectionbir de (bu sırayla) finallybunun gibi, bloğun onlarla bittiğinde şey:

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 */}
    }
}

finallyBlok hafif (boş kontrolü önlemek için) içine geliştirilebilir:

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

Ancak yine de, bu son derece ayrıntılıdır, bu nedenle genellikle nesneleri sıfır güvenli yardımcı yöntemlerde kapatmak için bir yardımcı sınıf kullanırsınız ve finallyblok şöyle bir şey olur:

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

Ve aslında, Apache Commons DbUtilsDbUtils tam olarak bunu yapan bir sınıfa sahiptir, böylece kendi sınıfınızı yazmaya gerek yoktur.


3
Harika yardım, teşekkürler! Conn! = Null ifadelerini anlamadım veya düşünmedim.
onaclov2000

1
@ onaclov2000 Evet rs, ps, connolabilir nullnerede kod sonları bağlı. Bu yüzden bu "güvenli" model olarak bilinir.
Pascal Thivent

12
@Pascal Thivent: Aslında hepsini kapatmamıza gerek yok. "Core Java Volume two - Advanced Features" kitabı şunu yazdı: closeBir Statementnesnenin yöntemi ResultSet, ifade açık bir sonuç kümesine sahipse ilişkili olanı otomatik olarak kapatır . Benzer bir şekilde, closebir yöntem Connectionsınıfının tüm kapatır Statementsarasında Connection.
Majid Azimi

12
@Majid: Havuzlanmış bir bağlantı olmadığı sürece. İfadeler daha sonra sızdırılır.
BalusC

1
@BalusC: Havuzlanmış bir bağlantı bağlantı.close () yöntemini kullanarak kapatıldığında ne olduğunu açıklayabilir misiniz
Krsna Chaitanya

61

Kullanımdan sonra veritabanı / kaynak nesnelerini kapatmak her zaman daha iyidir. Bloktaki bağlantıyı, sonuç kümesini ve ifade nesnelerini kapatmak daha iyidir finally.

Java7'ye kadar, tüm bu kaynakların bir finallyblok kullanılarak kapatılması gerekir . Java 7 kullanıyorsanız, kaynakları kapatmak için aşağıdaki işlemleri yapabilirsiniz.

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

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

Artık con, stmt ve rs nesneleri try bloğunun bir parçası haline gelir ve java, kullanımdan sonra bu kaynakları otomatik olarak kapatır.

Umarım yardımcı olmuşumdur.


Ya benim ifadem örtükse, yani bloğun ResultSet rs = conn.createStatement().executeQuery(sql);içindeyse try?
Antares42

1
Kapanış için final {} bloğunda bunlara referans veremezsiniz. Bir istisna atılırsa, ResultSet'in close () yöntemi asla çağrılmayacaktır
Dan,

Onları kapatmazsam ne olur?
Alex78191

onları kapatmazsanız bellek sızıntıları olabilir.
Yadu Krishnan

14

Sadece Statementve kapatmak yeterlidir Connection. ResultSetNesneyi açıkça kapatmaya gerek yoktur .

Java belgeleri hakkında şunları söylüyor java.sql.ResultSet:

Bir ResultSet nesnesi, söz konusu Statement nesnesi kapatıldığında, yeniden çalıştırıldığında veya birden çok sonuç dizisinden sonraki sonucu almak için kullanıldığında, onu oluşturan Statement nesnesi tarafından otomatik olarak kapatılır.


Yorumlarınız için teşekkürler BalusC: "Buna güvenmem. Bazı JDBC sürücüleri bu konuda başarısız oluyor."


25
Ben buna güvenmezdim. Bazı JDBC sürücüleri bu konuda başarısız olur. Örneğin "Maksimum açık imleç sayısı aşıldı" vb. Oracle ile açık tüm kaynakları açıkça kapatın, bahane yok.
BalusC

1
O zaman teknik özelliklere uymayan sürücüleri kullanmak istemiyorum
Enerccio

2
BalusC'nin de belirttiği gibi, belirli bir sağlayıcıya bağımlılığı sabitlemek yerine bağlantıyı açıkça kapatmak iyi bir savunma programlamadır.
michaelok

11

Evet. Sonuç kümesini, ifadeyi ve bağlantıyı kapatmanız gerekir. Bağlantı bir havuzdan geldiyse, kapatmak aslında onu yeniden kullanılmak üzere havuza geri gönderir.

Bunu genellikle bir finally{}blokta yapmanız gerekir , öyle ki bir istisna atılırsa, yine de bunu kapatma şansınız olur.

Birçok çerçeve sizin için bu kaynak tahsisi / serbest bırakma sorunuyla ilgilenecektir. örneğin Spring'in JdbcTemplate'i . Apache DbUtils , boş olsun ya da olmasın (ve kapanışta istisnaları yakalama) sonuç kümesini / ifadesini / bağlantıyı kapattıktan sonra bakacak yöntemlere sahiptir, bu da yardımcı olabilir.


1
"Nihayet" tutulmasını yerleştirdiğimde, bunun yanlış olduğunu söyleyerek onu vurgulamayı sever. bu yakalama bloklarından sonra mı gitmeli?
onaclov2000

Evet. Sonunda {} catch {} try {}. {} Yakalama isteğe bağlıdır, btw. Tıpkı nihayet {}
Brian Agnew

"Yakın" ifadelerini nihayet taşıdım, ama sadece "sqlexception" diyorlar, herhangi bir öneriniz var mı?
onaclov2000

1
close () bir SQLException oluşturur. Bunu halletmelisin. Bunu sessizce ele almak için DbUtils.closeQuietly () konusuna bakın.
Brian Agnew

> Conn.close () oluşmazsa gerçekten ne oluyor?
Alex78191

8

Aslında, en iyisi bir kaynakla deneme bloğu kullanırsanız, deneme bloğundan çıktığınızda Java sizin için tüm bağlantıları kapatır.

Bunu AutoClosable uygulayan herhangi bir nesne ile yapmalısınız.

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.");
}

GetDatabaseConnection çağrısı sadece yapılmıştır. Bunu, size bir JDBC SQL bağlantısı veya bir havuzdan bağlantı sağlayan bir çağrı ile değiştirin.


Yani bu durumda bağlantıyı manuel olarak kapatmanız gerekmez mi?
Colin D

1
Doğru. Bağlantıyı açıkça kapatmanız gerekmez. Deneme kodu bloğunun sonuna ulaşıldığında kapanacaktır.
Joe

7

Evet, Bağlantıyı kapatmanız gerekiyor. Aksi takdirde, veritabanı istemcisi tipik olarak soket bağlantısını ve diğer kaynakları açık tutacaktır.


... çıkana kadar. Bu, istemci ve sunucu tarafındaki çeşitli sınırlı kaynakları bağlar. Bir istemci bu tür bir şeyi çok fazla yaparsa, istemcinin kendisi, veritabanı hizmeti ve hatta istemci veya sunucu makinesinde çalışan diğer uygulamalar için sorunlara neden olabilir.
Stephen C
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.