JDBC'de bir bağlantı havuzu nasıl kurulur?


111

Bir JDBC bağlantı havuzunun nasıl kurulacağına dair örnekler veya bağlantılar sağlayabilen var mı?

Google'da arama yapmaktan bunu yapmanın birçok farklı yolunu görüyorum ve bu oldukça kafa karıştırıcı.

Sonuçta bir java.sql.Connectionnesneyi döndürmek için koda ihtiyacım var , ancak başlamakta sorun yaşıyorum ... herhangi bir öneri hoş geldiniz.

Güncelleme: Havuzlanmış bağlantı uygulamaları yok mu javax.sqlveya java.sqlyok mu? Bunları kullanmak neden en iyisi olmasın?


8
Hayır, stok JDBC Bağlantı havuzu sağlamaz. Bunun için ayrı bir kitaplığa ihtiyacınız var. Çoğu uygulama sunucusu ve servlet kapsayıcısında Bağlantı havuzları bulunur. Ayrıca, JPA uygulamaları tipik olarak uygulamaları da sağlar.
Will Hartung

3
Günümüz Java kullanıcıları için bir güncelleme. JDBC 3.0+ (Java 6'da kullanıldığına inanıyorum?) Havuzlanmış DB bağlantıları için bir uygulamaya sahiptir. Java 7, JDBC 4 ve Java 8 JDBC 4.1 kullanır.
BRasmussen

1
Bağlantı havuzu oluşturma için JDBC 3.0 API ile ilgili olarak: progress.com/tutorials/jdbc/jdbc-jdbc-connection-pooling
Arto Bendiken

Yanıtlar:


102

Bağımsız bir bağlantı havuzuna ihtiyacınız varsa, tercihim DBCP yerine C3P0'a gider (bu önceki cevapta bahsettiğim ), ağır yük altında DBCP ile çok fazla sorun yaşadım. C3P0 kullanmak son derece basittir. Gönderen belgeler :

ComboPooledDataSource cpds = new ComboPooledDataSource();
cpds.setDriverClass( "org.postgresql.Driver" ); //loads the jdbc driver
cpds.setJdbcUrl( "jdbc:postgresql://localhost/testdb" );
cpds.setUser("swaldman");
cpds.setPassword("test-password");

// the settings below are optional -- c3p0 can work with defaults
cpds.setMinPoolSize(5);
cpds.setAcquireIncrement(5);
cpds.setMaxPoolSize(20);

// The DataSource cpds is now a fully configured and usable pooled DataSource 

Ancak bir uygulama sunucusunun içinde çalışıyorsanız, sağladığı yerleşik bağlantı havuzunu kullanmanızı tavsiye ederim. Bu durumda, yapılandırmanız (uygulama sunucunuzun belgelerine bakın) ve JNDI aracılığıyla bir DataSource almanız gerekir:

DataSource ds = (DataSource) new InitialContext().lookup("jdbc/myDS");

1
Aynen öyle. Yıllardır bir yük altında DBCP'nin kilitlendiğini gözlemliyorum. Sürümden sonraki sürüm.
Vasiliy

evet ama C3P0 ayrıca, BoneCP ile en iyi deneyimi yaşadım
Nicolas Mommaerts

1
BoneCP gibi görünüyor olmuştur kaldırılmış lehine HikariCP . HikariCP ayrıca aşağıdaki cevapta da belirtilmiştir .
kaartic

19

Genellikle bir bağlantı havuzuna ihtiyacınız varsa, bazı yönetilen ortamlarda çalışan, yani bir uygulama sunucusunun içinde çalışan bir uygulama yazarsınız. Bu durumda , diğer seçenekleri denemeden önce uygulama sunucunuzun hangi bağlantı havuzu olanaklarını sağladığını kontrol ettiğinizden emin olun .

Kutudan çıkar çıkmaz çözüm, diğer uygulama sunucuları tesisleriyle en iyi entegre olacaktır. Ancak bir uygulama sunucusu içinde çalışmıyorsanız, Apache Commons DBCP Bileşenini tavsiye ederim . Yaygın olarak kullanılır ve çoğu uygulamanın gerektirdiği tüm temel havuzlama işlevlerini sağlar.


18

HikariCP

Modern, hızlı, basit. Her yeni proje için kullanıyorum. C3P0'a göre çok tercih ederim, diğer havuzları çok iyi bilmiyorum.


18

Tekerleği yeniden icat etmeyin.

Hazır bulunan 3. taraf bileşenlerinden birini deneyin:

Apache DBCP, javax.sql.DataSource havuzunun nasıl kurulacağına dair farklı bir örnekle birlikte gelir . İşte başlamanıza yardımcı olabilecek bir örnek .


1
C3P0 olarak adlandırılır. DBCP tek bir iş parçacığına erişimi kilitlediğinden, bu arada çok iş parçacıklı ortamlarda DBCP'den daha performanslı.
BalusC

@BalusC. Düzeltme için teşekkürler disclecsia, beni daha iyi anladım. Bağlantının doğru olduğunu görebilirsiniz. :)
Alexander Pogrebnyak

1
@Mudassir. Spring -> static.springsource.com/projects/tc-server/2.0/admin/htmlsingle/… ' den Tomcat'e katkıda bulunan DBCP yerine bir drop-in yerine bakmanızı tavsiye ederim . Kullanmak için tüm Tomcat sunucusuna ihtiyacınız yok, sadece tek bir kavanoz tomcat-jdbc. Maven Central'dan edinebilirsiniz -> org.apache.tomcat:tomcat-jdbc:jar:7.0.22-> search.maven.org/…
Alexander Pogrebnyak

@AlexanderPogrebnyak: Teşekkürler Alexander, çok iyisin. Bir Axis web hizmetinde CP kullanmayı planlıyorum. Öneriniz hakkında düşünecekler. - Mudassir 7 dakika önce
Mudassir

17

Commons-dbcp kitaplığını kullanmanızı tavsiye ederim . Nasıl kullanılacağına dair listelenen çok sayıda örnek var, işte basit olanı hareket ettirmenin bağlantısı . Kullanım çok basit:

 BasicDataSource ds = new BasicDataSource();
 ds.setDriverClassName("oracle.jdbc.driver.OracleDriver")
 ds.setUsername("scott");
 ds.setPassword("tiger");
 ds.setUrl(connectURI);
 ...
 Connection conn = ds.getConnection();

Veri kaynağını yalnızca bir kez oluşturmanız gerekir, bu nedenle, bunu nasıl yapacağınızı bilmiyorsanız belgeleri okuduğunuzdan emin olun. Kaynakları sızdırmamak için JDBC ifadelerini nasıl düzgün yazacağınızın farkında değilseniz, bu Wikipedia sayfasını da okumak isteyebilirsiniz .


8
Bu gerçekten bir bağlantı havuzu oluşturur mu?
um

@llm Elbette! javax.sql.DataSourceArabirimin tanımı "Bağlantı göllenmesi“bir uygulamasını içeren (yanında, ben zaten bir JDBC arayüzü ne olduğunu biliyorum).
Eddy

7

Çalıştığım yerde kullandığımız uygulama sunucusunda (hatırladığım kadarıyla Oracle Application Server 10g), havuzlama uygulama sunucusu tarafından yapılıyor. Biz almak javax.sql.DataSourcebir bir Jndi aramasını kullanarak javax.sql.InitialContext.

bunun gibi bir şey yaptı

try {     
   context = new InitialContext();
   jdbcURL = (DataSource) context.lookup("jdbc/CachedDS");
   System.out.println("Obtained Cached Data Source ");
}
catch(NamingException e)   
{  
    System.err.println("Error looking up Data Source from Factory: "+e.getMessage());
}

(Bu kodu biz yazmadık, bu belgeden kopyalandı .)


5

havuz

  • Havuzlama Mekanizması, Nesneleri önceden oluşturmanın yoludur. Bir sınıf yüklendiğinde.
  • Uygulamayı iyileştirir performance[Nesne-Verileri üzerinde herhangi bir eylemi gerçekleştirmek için aynı nesnelerin kullanılmasıyla] & memory[birçok nesnenin tahsis edilmesi ve ayrılması önemli bir bellek yönetimi ek yükü oluşturur].
  • Çöp toplama yükünü azaltarak aynı Object'i kullandığımız için nesne temizliği gerekli değildir.

« ObjectHavuz [ havuz, StringSabit Havuz, ThreadHavuz, Bağlantı havuzu]

Dize Sabit havuzu

  • Dize değişmez havuzu, her farklı dize değerinin yalnızca bir kopyasını tutar. değişmez olması gerekir.
  • İntern yöntemi çağrıldığında, eşittir yöntemini kullanarak havuzda aynı içeriğe sahip nesne kullanılabilirliğini kontrol eder. «Dize kopyası Havuzda mevcutsa referansı döndürür. «Aksi takdirde, String nesnesi havuza eklenir ve referansı döndürür.

Örnek: Havuzdan Benzersiz Nesneyi doğrulamak için dize .

public class StringPoolTest {
    public static void main(String[] args) { // Integer.valueOf(), String.equals()
        String eol = System.getProperty("line.separator"); //java7 System.lineSeparator();

        String s1 = "Yash".intern();
        System.out.format("Val:%s Hash:%s SYS:%s "+eol, s1, s1.hashCode(), System.identityHashCode(s1));
        String s2 = "Yas"+"h".intern();
        System.out.format("Val:%s Hash:%s SYS:%s "+eol, s2, s2.hashCode(), System.identityHashCode(s2));
        String s3 = "Yas".intern()+"h".intern();
        System.out.format("Val:%s Hash:%s SYS:%s "+eol, s3, s3.hashCode(), System.identityHashCode(s3));
        String s4 = "Yas"+"h";
        System.out.format("Val:%s Hash:%s SYS:%s "+eol, s4, s4.hashCode(), System.identityHashCode(s4));
    }
}

Tip-4 kullanarak bağlantı havuzu Sürücü 3. parti kütüphaneleri kullanılarak [ DBCP2, c3p0, Tomcat JDBC]

Type 4 - The Thin driver converts JDBC calls directly into the vendor-specific database protocol Ex[Oracle - Thick, MySQL - Quora]. wiki

Bağlantı havuzu mekanizmasında, sınıf yüklendiğinde physical JDBC connectionnesneleri alır ve kullanıcıya sarmalanmış bir fiziksel bağlantı nesnesi sağlar. PoolableConnectiongerçek bağlantının etrafındaki bir sarmalayıcıdır.

  • getConnection()bağlantı nesne havuzundan serbest sarılmış bağlantılardan birini seçin ve onu geri döndürür.
  • close() kapatmak yerine sarmalanmış bağlantıyı havuza geri döndürür.

Örnek: ~ DBCP2 Bağlantı Havuzunu Java 7 ile Kullanma [ try-with-resources]

public class ConnectionPool {
    static final BasicDataSource ds_dbcp2 = new BasicDataSource();
    static final ComboPooledDataSource ds_c3p0 = new ComboPooledDataSource();
    static final DataSource ds_JDBC = new DataSource();

    static Properties prop = new Properties();
    static {
        try {
            prop.load(ConnectionPool.class.getClassLoader().getResourceAsStream("connectionpool.properties"));

            ds_dbcp2.setDriverClassName( prop.getProperty("DriverClass") );
            ds_dbcp2.setUrl( prop.getProperty("URL") );
            ds_dbcp2.setUsername( prop.getProperty("UserName") );
            ds_dbcp2.setPassword( prop.getProperty("Password") );
            ds_dbcp2.setInitialSize( 5 );

            ds_c3p0.setDriverClass( prop.getProperty("DriverClass") );
            ds_c3p0.setJdbcUrl( prop.getProperty("URL") );
            ds_c3p0.setUser( prop.getProperty("UserName") );
            ds_c3p0.setPassword( prop.getProperty("Password") );
            ds_c3p0.setMinPoolSize(5);
            ds_c3p0.setAcquireIncrement(5);
            ds_c3p0.setMaxPoolSize(20);

            PoolProperties pool = new PoolProperties();
            pool.setUrl( prop.getProperty("URL") );
            pool.setDriverClassName( prop.getProperty("DriverClass") );
            pool.setUsername( prop.getProperty("UserName") );
            pool.setPassword( prop.getProperty("Password") );
            pool.setValidationQuery("SELECT 1");// SELECT 1(mysql) select 1 from dual(oracle)

            pool.setInitialSize(5);
            pool.setMaxActive(3);
            ds_JDBC.setPoolProperties( pool );
        } catch (IOException e) {   e.printStackTrace();
        } catch (PropertyVetoException e) { e.printStackTrace(); }
    }

    public static Connection getDBCP2Connection() throws SQLException {
        return ds_dbcp2.getConnection();
    }

    public static Connection getc3p0Connection() throws SQLException {
        return ds_c3p0.getConnection();
    }

    public static Connection getJDBCConnection() throws SQLException {
        return ds_JDBC.getConnection();
    }
}
public static boolean exists(String UserName, String Password ) throws SQLException {
    boolean exist = false;
    String SQL_EXIST = "SELECT * FROM users WHERE username=? AND password=?";
    try ( Connection connection = ConnectionPool.getDBCP2Connection();
          PreparedStatement pstmt = connection.prepareStatement(SQL_EXIST); ) {
        pstmt.setString(1, UserName );
        pstmt.setString(2, Password );

        try (ResultSet resultSet = pstmt.executeQuery()) {
            exist = resultSet.next(); // Note that you should not return a ResultSet here.
        }
    }
    System.out.println("User : "+exist);
    return exist;
}

jdbc:<DB>:<drivertype>:<HOST>:<TCP/IP PORT>:<dataBaseName> jdbc:oracle:thin:@localhost:1521:myDBName jdbc:mysql://localhost:3306/myDBName

connectionpool.properties

URL         : jdbc:mysql://localhost:3306/myDBName
DriverClass : com.mysql.jdbc.Driver
UserName    : root
Password    :

Web Uygulaması: Temel DB ile bağlantıyı yeniden açmak için tüm bağlantılar kapatıldığında bağlantı sorununu önlemek için [MySQL "bekleme süresi" varsayılan 8 saat].

Bunu, testOnBorrow = true ve validationQuery = "SELECT 1" ayarlayarak Her Bağlantıyı Test Etmek için yapabilirsiniz ve kullanımdan kaldırıldığı için MySQL sunucusu için otomatik yeniden bağlantı özelliğini kullanmayın. konu

===== ===== context.xml ===== =====
<?xml version="1.0" encoding="UTF-8"?>
<!-- The contents of this file will be loaded for a web application -->
<Context>
    <Resource name="jdbc/MyAppDB" auth="Container" 
        factory="org.apache.tomcat.jdbc.pool.DataSourceFactory" 
        type="javax.sql.DataSource" 

        initialSize="5" minIdle="5" maxActive="15" maxIdle="10"

        testWhileIdle="true"
            timeBetweenEvictionRunsMillis="30000"

        testOnBorrow="true"
            validationQuery="SELECT 1"
            validationInterval="30000"


        driverClassName="com.mysql.jdbc.Driver" 
        url="jdbc:mysql://localhost:3306/myDBName" 
        username="yash" password="777"
    />
</Context>

===== ===== web.xml ===== =====
<resource-ref>
    <description>DB Connection</description>
    <res-ref-name>jdbc/MyAppDB</res-ref-name>
    <res-type>javax.sql.DataSource</res-type>
    <res-auth>Container</res-auth>
</resource-ref>
===== ===== DBOperations ===== =====
servlet «   init() {}
Normal call used by sevlet  « static {}

static DataSource ds;
static {
    try {
        Context ctx=new InitialContext();
        Context envContext = (Context)ctx.lookup("java:comp/env");
        ds  =   (DataSource) envContext.lookup("jdbc/MyAppDB");
    } catch (NamingException e) {   e.printStackTrace();    }
}

Şunlara da bakın:


String Sabiti havuzu örneğinde, "Havuzda String-copy varsa [.equals ()], referansı döndürür.« Aksi takdirde, String nesnesi havuza eklenir ve referansı döndürür. " Ama public class StringPoolTestsadece 2 void yöntemi vardır, böylece hiçbir şey döndürmezler. Bu kod aslında dize havuzunu yönetme sürecinden geçiyor mu? Herhangi bir argüman kullanmıyor gibi görünüyor.
jeffery_the_wind

@jeffery_the_wind: - sadece havuz kavramını bilmek, dizi havuzu doğrulaması için hashCode, IdentityHashCode yöntemlerini kullandım . kodu değiştirdi ...
Yash

Pardon, s1tanımlanmadı?
jeffery_the_wind

Tamam, her şeyi gördüğümden emin olmak istedim. Bunun üzerinde çalışacağım. ConnectionPoolSınıfınıza daha yakın bir şeye ihtiyacım olacak . Çok teşekkürler.
jeffery_the_wind

5

2017'nin sonlarında Proxool, BoneCP, C3P0, DBCP şu anda çoğunlukla feshedildi. HikariCP (2012'de yaratıldı) umut verici görünüyor, bildiğim her şeyin kapılarını patlatıyor. http://www.baeldung.com/hikaricp

Proxool'un bir takım sorunları vardır:
- Ağır yük altında maksimum bağlantı sayısını aşabilir ve maksimumun altına dönmeyebilir
- Bağlantıların süresi dolduktan sonra bile minimum bağlantılara geri dönmeyebilir
- Tüm havuzu (ve tüm sunucu / istemci iş parçacıklarını) kilitleyebilir HouseKeeper iş parçacığı sırasında veritabanına bağlanmada sorun yaşarsa (.setQueryTimeout kullanmaz)
- HouseKeeper iş parçacığı, işlemi için bağlantı havuzu kilidine sahipken, Prototyper iş parçacığının bağlantıları yeniden oluşturmasını ister (tarama), bu da yarış durumuna / kilitlenmesine neden olabilir. Bu yöntem çağrılarında, son parametre her zaman döngü sırasında sweep: false olmalıdır, yalnızca altında sweep: true.
- HouseKeeper, sonunda yalnızca tek PrototypeController taramasına ihtiyaç duyar ve daha fazlasına sahiptir [yukarıda belirtilmiştir]
- HouseKeeper iş parçacığı, hangi bağlantıların süresinin dolmuş olabileceğini görmeden önce bağlantıları test etmek için kontrol eder [güvenlik duvarındaki diğer zaman aşımları nedeniyle kesilmiş / sonlandırılmış olabilecek süresi dolmuş bağlantıların test edilmesine ilişkin bazı riskler, vb.]
- Projede bitmemiş kod (tanımlanmış özellikler ancak üzerinde işlem yapılmadı)
- Tanımlanmadıysa Varsayılan maksimum bağlantı ömrü 4 saattir (aşırı)
- HouseKeeper iş parçacığı havuz başına her beş saniyede bir çalışır (aşırı)

Kodu değiştirebilir ve bu iyileştirmeleri yapabilirsiniz. Ancak 2003'te oluşturulduğu ve 2008'de güncellendiği için, hikaricp gibi çözümlerin kullandığı yaklaşık 10 yıllık java iyileştirmelerinden yoksun.


4

Başkalarının da yanıtladığı gibi, Apache Dbcp veya c3p0'dan muhtemelen memnun kalacaksınız . Her ikisi de popüler ve iyi çalışıyor.

Şüphenizle ilgili olarak

Javax.sql veya java.sql havuzlanmış bağlantı uygulamalarına sahip değil mi? Bunları kullanmak neden en iyisi olmasın?

Uygulamalar yerine arayüzler ve bazı destek sınıfları sağlamazlar, yalnızca üçüncü taraf kitaplıkları (havuzlar veya sürücüler) uygulayan programcılar için geçerlidir. Normalde ona bakmazsın bile. Kodunuz, havuzunuzdaki bağlantılarla aynı "düz" bağlantılar gibi şeffaf bir şekilde ilgilenmelidir.


4

Vibur DBCP , bu amaç için başka bir kitaplıktır. Hibernate, Spring + Hibernate ile veya programlı olarak kullanılmak üzere nasıl yapılandırılacağını gösteren birkaç örnek web sitesinde bulunabilir: http://www.vibur.org/

Ayrıca, açıklamaya bakın burada .


3

Apache Commons'ın bu amaçla bir kitaplığı vardır: DBCP . Havuzlarınızın etrafında garip gereksinimleriniz olmadıkça, umduğunuzdan daha zor ve incelikli olacağı için bir kitaplık kullanırım.


1

UCP kullanmayı düşünmelisiniz. Evrensel Bağlantı Havuzu (UCP) bir Java bağlantı havuzudur. Zengin özelliklere sahip bir bağlantı havuzudur ve Oracle'ın Gerçek Uygulama Kümeleri (RAC), ADG, DG veritabanları ile sıkı bir şekilde entegre edilmiştir.

UCP hakkında daha fazla ayrıntı için bu sayfaya bakın .


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.