Havuzdaki JDBC Bağlantılarını Kapatma


109

JDBC'yi kullanmak için standart kod bölümümüz ...

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

Soru 1: Bağlantı Havuzu kullanılırken sonunda Bağlantı kapatılmalı mı? Öyleyse, havuz oluşturmanın amacı kaybolmaz mı? Ve değilse, DataSource belirli bir Connection örneğinin serbest kaldığını ve yeniden kullanılabileceğini nasıl biliyor? Bu konuda biraz kafam karıştı, herhangi bir işaretçi takdir etti.

Soru 2: Aşağıdaki yöntem standarda yakın bir şey mi? Havuzdan bir bağlantı alma girişimi gibi görünüyor ve DataSource kurulamıyorsa, eski moda DriverManager'ı kullanın. Çalışma zamanında hangi parçanın yürütüldüğünden bile emin değiliz. Yukarıdaki soruyu tekrar edersek, böyle bir yöntemden çıkan Bağlantı kapatılmalı mı?

Teşekkürler - 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);
}

Düzenleme: Yığın izi görmediğimiz için havuzlanmış bağlantıyı elde ettiğimizi düşünüyorum.

Yanıtlar:


121

Bağlantı Havuzu kullanılırken sonunda Bağlantı kapatılmalı mı? Öyleyse, havuz oluşturmanın amacı kaybolmaz mı? Ve değilse, DataSource belirli bir Connection örneğinin serbest kaldığını ve yeniden kullanılabileceğini nasıl biliyor? Bu konuda biraz kafam karıştı, herhangi bir işaretçi takdir etti.

Evet, havuzlanmış bağlantıyı kesinlikle kapatmanız gerekir. Aslında gerçek bağlantının etrafındaki bir sarmalayıcı. Kapakların altında havuza olan asıl bağlantıyı serbest bırakacaktır. Gerçek bağlantının gerçekten kapatılıp kapatılmayacağına veya yeni bir getConnection()arama için yeniden kullanılıp kullanılmayacağına karar vermek havuza kalmıştır . Bu nedenle, bir bağlantı havuzu kullanıp kullanmadığınıza bakılmaksızın, tüm JDBC kaynaklarını her zaman onları elde ettiğiniz blok finallybloğunda ters sırayla kapatmalısınız try. Java 7'de bu, ifade kullanılarak daha da basitleştirilebilir try-with-resources.


Aşağıdaki yöntem standarda yakın bir şey mi? Havuzdan bir bağlantı alma girişimi gibi görünüyor ve DataSource kurulamıyorsa, eski moda DriverManager'ı kullanın. Çalışma zamanında hangi parçanın yürütüldüğünden bile emin değiliz. Yukarıdaki soruyu tekrar edersek, böyle bir yöntemden çıkan Bağlantı kapatılmalı mı?

Örnek oldukça korkutucu. DataSourceUygulama çapında bir DB yapılandırma sınıfının bazı yapıcı / başlatmasında uygulamanın başlangıcı sırasında yalnızca bir kez aramanız / başlatmanız gerekir . Ardından getConnection(), uygulamanın geri kalan ömrü boyunca tek ve aynı veri kaynağını çağırın . Senkronizasyona veya boş kontrollere gerek yok.

Ayrıca bakınız:


Yaptığı şey bu (bir kez başlat), değil mi? ds bir örnek değişkendir ve if (ds == null) ... başlatma kısmıdır.
Manidip Sengupta

Kontrolleri her seferinde bir get-yönteminde getConnection()yapmak garip. Sadece aynı sınıfın c'tor veya başlatma bloğunda, senkronizasyon / nullchecks olmadan yapın. Yalnızca bir kez aranacak. Daha fazla ipucu ve başlangıç ​​örneği için bu makaleyi faydalı bulabilirsiniz .
BalusC

Mükemmel makale, BalusC. Benim uğraştığım sınıf, DTO'ları kullanarak Veri Katmanını büyük ölçüde uygular. Size katılıyorum, başlatma yapıcıda olmalıdır. Şimdi, bu sınıfın her biri yerel değişkenler olarak conn, stmt ve rset içeren bir ton yöntemi vardır, bağlantılar bir try bloğundadır ve son olarak 1 satırlık csrClose (conn, stmt, rset) çağrısı vardır, burada 3 kapalıdır (ters sırada). Şimdi, örnekte geliştirdiğiniz DTO, bir DB tablo satırının ayna görüntüsüdür. Birleştirmelerle (ve diğer maddelerle) karmaşık SQL sorgularımız var, bu tür sonuçlar için DAO'ların nasıl geliştirileceğine dair bir makaleniz var mı?
Manidip Sengupta

2
@yat: Sen, çağır close()içinde hepsinde finallyaynı blok tryedindiğiniz nereye kadar blokta / onları yarattı. Bu, havuzlanmış bir bağlantı olup olmadığından tamamen bağımsızdır.
BalusC

1
@iJava: Bu havuz, ne yaptığı hakkında kesin bir fikri olmayan bir amatör tarafından yazılmıştır. Görmezden gelin ve gerçek bir kitaplığa gidin. Örneğin HikariCP.
BalusC

22

Havuzlar genellikle size, close () yönteminin geçersiz kılındığı ve genellikle Bağlantıyı havuza döndüren sarmalanmış bir Bağlantı nesnesi döndürür. Close () çağrısı tamam ve muhtemelen hala gereklidir.

Bir close () yöntemi muhtemelen şöyle görünecektir:

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

İkinci sorunuz için, alt bloğun hiç çalışıp çalışmadığını göstermek için bir kaydedici ekleyebilirsiniz. Veritabanı bağlantılarınızın yapılandırması için yalnızca bir yolu veya diğerini isteyeceğinizi tahmin ediyorum. Veritabanı erişimlerimiz için yalnızca bir havuz kullanıyoruz. Her iki durumda da, sızıntıları önlemek için bağlantının kapatılması oldukça önemli olacaktır.


Katılıyorum, bir kaydedicimiz var ve bu da burada kullanılabilir. Bir Nesneyi nasıl
sarabileceğiniz

1
Calling close() is OK and probably still required.Havuz uygular bazı kurtarma stratejisi sürece, bağlantı sızdırıyor yakın aramayacağım
Svarog

0

Aslında, bağlantı yönetimine yönelik en iyi yaklaşım, bunları herhangi bir yerde herhangi bir kodda toplamamaktır.

Bağlantıları açan ve kapatan tek konum olan bir SQLExecutor sınıfı oluşturun.

Uygulamanın geri kalanı, havuzdan bağlantılar almak ve her yerde yönetmek (veya yanlış yönetmek) yerine ifadeleri uygulayıcıya pompalar.

Yürütücünün istediğiniz kadar örneğine sahip olabilirsiniz, ancak hiç kimse kendi adına bağlantıları açan ve kapatan kod yazmamalıdır.

Bu, kullanışlı bir şekilde tüm SQL'inizi tek bir kod kümesinden kaydetmenize olanak tanır.

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.