Bagaimana cara membuat kumpulan koneksi di JDBC?

111

Adakah yang bisa memberikan contoh atau tautan tentang cara membuat kumpulan koneksi JDBC?

Dari pencarian google saya melihat banyak cara berbeda untuk melakukan ini dan itu agak membingungkan.

Pada akhirnya saya memerlukan kode untuk mengembalikan java.sql.Connectionobjek, tetapi saya mengalami kesulitan untuk memulai .. saran apa pun diterima.

Pembaruan: Apakah tidak javax.sqlatau java.sqlmemiliki implementasi koneksi gabungan? Mengapa tidak lebih baik menggunakan ini?

llm
sumber
8
Tidak, stok JDBC tidak menyediakan penggabungan koneksi. Anda membutuhkan perpustakaan terpisah untuk itu. Sebagian besar server aplikasi dan kontainer servlet memiliki kumpulan koneksi yang disertakan dengannya. Selain itu, implementasi JPA biasanya juga menyediakan implementasi.
Will Hartung
3
Pembaruan untuk pengguna Java modern. JDBC 3.0+ (yang saya yakini digunakan di Java 6?) Memiliki implementasi untuk koneksi DB yang dikumpulkan. Java 7 menggunakan JDBC 4, dan Java 8 JDBC 4.1.
BRasmussen
1
Mengenai API JDBC 3.0 untuk penggabungan koneksi: progress.com/tutorials/jdbc/jdbc-jdbc-connection-pooling
Arto Bendiken

Jawaban:

102

Jika Anda memerlukan kumpulan koneksi mandiri, preferensi saya pergi ke C3P0 daripada DBCP (yang telah saya sebutkan dalam jawaban sebelumnya ), saya hanya mengalami terlalu banyak masalah dengan DBCP di bawah beban berat. Menggunakan C3P0 sangat sederhana. Dari dokumentasi :

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 

Tetapi jika Anda menjalankan di dalam server aplikasi, saya akan merekomendasikan untuk menggunakan kumpulan koneksi built-in yang disediakannya. Dalam hal ini, Anda harus mengonfigurasinya (lihat dokumentasi server aplikasi Anda) dan untuk mengambil Sumber Data melalui JNDI:

DataSource ds = (DataSource) new InitialContext().lookup("jdbc/myDS");
Pascal Thivent
sumber
1
Ditto, itu. Saya telah mengamati kebuntuan DBCP di bawah beban selama bertahun-tahun sekarang. Versi demi versi.
Vasiliy
ya tapi juga C3P0, saya memiliki pengalaman terbaik dengan BoneCP
Nicolas Mommaerts
1
Sepertinya BoneCP sudah usang dan mendukung HikariCP . HikariCP juga disebutkan dalam jawaban di bawah ini .
kaartic
19

Biasanya jika Anda memerlukan kumpulan koneksi, Anda menulis aplikasi yang berjalan di beberapa lingkungan yang dikelola, yaitu Anda berjalan di dalam server aplikasi. Jika demikian, pastikan untuk memeriksa fasilitas penggabungan koneksi yang disediakan server aplikasi Anda sebelum mencoba opsi lain.

Solusi out-of-the box akan menjadi yang terbaik yang terintegrasi dengan fasilitas server aplikasi lainnya. Namun jika Anda tidak menjalankan di dalam server aplikasi, saya akan merekomendasikan Komponen DBCP Apache Commons . Ini banyak digunakan dan menyediakan semua fungsionalitas penggabungan dasar yang dibutuhkan sebagian besar aplikasi.

Tendayi Mawushe
sumber
18

HikariCP

Ini modern, cepat, sederhana. Saya menggunakannya untuk setiap proyek baru. Saya lebih suka itu daripada C3P0, tidak tahu kolam lain terlalu baik.

tobijdc.dll
sumber
18

Jangan menemukan kembali roda.

Coba salah satu komponen pihak ketiga yang tersedia:

  • Apache DBCP - Yang ini digunakan secara internal oleh Tomcat, dan oleh Anda benar-benar.
  • c3p0

Apache DBCP hadir dengan contoh berbeda tentang cara menyiapkan javax.sql.DataSource penggabungan . Berikut ini satu contoh yang dapat membantu Anda memulai.

Alexander Pogrebnyak
sumber
1
Ini disebut C3P0. Ini jauh lebih berkinerja daripada DBCP di lingkungan multithread karena DBCP mengunci akses ke satu utas.
BalusC
@Tokopedia Terima kasih atas koreksinya, saya disclecsiamenjadi lebih baik dari saya. Anda dapat melihat bahwa tautannya benar. :)
Alexander Pogrebnyak
1
@Tokopedia Saya akan merekomendasikan melihat pengganti drop-in untuk DBCP yang dikontribusikan ke Tomcat dari Spring -> static.springsource.com/projects/tc-server/2.0/admin/htmlsingle/… . Anda tidak perlu seluruh server Tomcat untuk menggunakannya, cukup satu stoples tomcat-jdbc. Anda bisa mendapatkannya dari Maven Central -> org.apache.tomcat:tomcat-jdbc:jar:7.0.22-> search.maven.org/…
Alexander Pogrebnyak
@AlexanderPogrebnyak: Terima kasih Alexander, terima kasih banyak. Saya berencana menggunakan CP dalam layanan web Axis. Akan memikirkan saran Anda. - Mudassir 7 menit yang lalu
Mudassir
17

Saya akan merekomendasikan menggunakan pustaka commons-dbcp . Ada banyak contoh yang terdaftar tentang cara menggunakannya, berikut adalah tautan ke langkah sederhana . Penggunaannya sangat sederhana:

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

Anda hanya perlu membuat sumber data satu kali, jadi pastikan Anda membaca dokumentasinya jika tidak tahu cara melakukannya. Jika Anda tidak mengetahui cara menulis pernyataan JDBC dengan benar sehingga Anda tidak membocorkan sumber daya, Anda juga mungkin ingin membaca halaman Wikipedia ini .

Eric Hauser
sumber
8
Apakah ini benar-benar membuat kumpulan koneksi?
Akan
@ll Tentu! The javax.sql.DataSourcedefinisi antarmuka mengandung sebuah implementasi dari "Connection pooling“(selain itu, saya pikir Anda sudah tahu apa antarmuka JDBC adalah).
Eddy
7

Di server aplikasi yang kami gunakan tempat saya bekerja (Oracle Application Server 10g, seingat saya), penggabungan ditangani oleh server aplikasi. Kami mengambil javax.sql.DataSourcemenggunakan pencarian JNDI dengan javax.sql.InitialContext.

itu melakukan sesuatu seperti ini

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

(Kami tidak menulis kode ini, itu disalin dari dokumentasi ini .)

Powerlord
sumber
5

Kolam

  • Mekanisme Pooling adalah cara membuat Objek terlebih dahulu. Saat kelas dimuat.
  • Ini meningkatkan aplikasi performance[Dengan menggunakan kembali objek yang sama untuk melakukan tindakan apa pun pada Object-Data] & memory[mengalokasikan dan mengalokasikan banyak objek menciptakan overhead manajemen memori yang signifikan].
  • Pembersihan objek tidak diperlukan karena kami menggunakan Objek yang sama, mengurangi beban pengumpulan Sampah.

«Pooling [ Objectpool, StringConstant Pool, ThreadPool, Connection pool]

Kumpulan string konstan

  • Kumpulan literal string hanya mempertahankan satu salinan dari setiap nilai string yang berbeda. yang harus tetap.
  • Ketika metode intern dipanggil, itu memeriksa ketersediaan objek dengan konten yang sama dalam kumpulan menggunakan metode sama. «Jika String-copy tersedia di Pool maka mengembalikan referensi. «Jika tidak, objek String ditambahkan ke pool dan mengembalikan referensi.

Contoh: String untuk memverifikasi Objek Unik dari kumpulan.

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

Kolam koneksi menggunakan Type-4 driver menggunakan perpustakaan pihak ke-3 [ 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

Dalam mekanisme Connection pool, ketika kelas dimuat, ia mengambil physical JDBC connectionobjek dan menyediakan objek koneksi fisik yang dibungkus kepada pengguna. PoolableConnectionadalah pembungkus di sekitar koneksi yang sebenarnya.

  • getConnection()pilih salah satu dari koneksi terbungkus bebas dari objectpool koneksi dan mengembalikannya.
  • close() alih-alih menutupnya, ia mengembalikan koneksi yang dibungkus kembali ke kumpulan.

Contoh: Menggunakan ~ DBCP2 Connection Pool dengan Java 7 [ 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    :

Aplikasi Web : Untuk menghindari masalah koneksi ketika semua koneksi ditutup [MySQL "wait_timeout" default 8 jam] untuk membuka kembali koneksi dengan DB yang mendasarinya.

Anda dapat melakukan ini untuk Menguji Setiap Koneksi dengan menyetel testOnBorrow = true dan validationQuery = "SELECT 1" dan jangan menggunakan autoReconnect untuk server MySQL karena sudah usang. isu

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

Lihat ini juga:

Yash
sumber
Dalam contoh kumpulan String Konstan, saya mengerti ketika Anda menulis "Jika salinan-String tersedia [.equals ()] di Kumpulan maka mengembalikan referensi.« Jika tidak, objek String ditambahkan ke kumpulan dan mengembalikan referensi. " Tetapi public class StringPoolTesthanya memiliki 2 metode void sehingga mereka tidak mengembalikan apa pun. Apakah kode tersebut benar-benar melalui proses pengelolaan kumpulan string? Ia bahkan tidak menggunakan argumen apapun.
jeffery_the_wind
@jeffery_the_wind: - itu hanya untuk mengetahui konsep kolam renang, kolam renang untuk string yang verifikasi saya hanya digunakan hashCode, identityHashCode methodes . memodifikasi kode ...
Yash
Maaf, s1tidak ditentukan?
jeffery_the_wind
Oke, hanya ingin memastikan bahwa saya melihat semuanya. Saya akan mengerjakannya. Apa yang saya perlukan untuk sesuatu yang lebih dekat dengan ConnectionPoolKelas Anda . Terima kasih banyak.
jeffery_the_wind
5

Di akhir 2017 Proxool, BoneCP, C3P0, DBCP sebagian besar tidak berfungsi saat ini. HikariCP (dibuat pada tahun 2012) tampaknya menjanjikan, menutup pintu dari hal lain yang saya ketahui. http://www.baeldung.com/hikaricp

Proxool memiliki sejumlah masalah:
- Di bawah beban berat dapat melebihi jumlah maksimum koneksi dan tidak kembali di bawah max
- Dapat mengatur untuk tidak kembali ke koneksi min bahkan setelah koneksi kedaluwarsa
- Dapat mengunci seluruh kumpulan (dan semua utas server / klien) jika mengalami masalah saat menyambungkan ke database selama utas HouseKeeper (tidak menggunakan .setQueryTimeout)
- utas HouseKeeper, saat memiliki kunci kumpulan koneksi untuk prosesnya, meminta utas Prototyper untuk membuat ulang koneksi (sapuan) yang dapat mengakibatkan kondisi balapan / kemacetan. Dalam panggilan metode ini, parameter terakhir harus selalu sweep: false selama pengulangan, hanya sweep: true di bawahnya.
- HouseKeeper hanya membutuhkan satu sapuan PrototypeController di akhir dan memiliki lebih banyak [disebutkan di atas]
- Thread HouseKeeper memeriksa pengujian koneksi sebelum melihat koneksi apa yang mungkin kedaluwarsa [beberapa risiko pengujian koneksi kedaluwarsa yang mungkin rusak / diakhiri melalui timeout lain ke DB di firewall, dll.]
- Proyek memiliki kode yang belum selesai (properti yang ditentukan tetapi tidak ditindaklanjuti)
- Masa pakai koneksi maks default jika tidak ditentukan adalah 4 jam (berlebihan)
- Utas HouseKeeper berjalan setiap lima detik per kumpulan (berlebihan)

Anda dapat mengubah kode dan melakukan peningkatan ini. Tapi seperti yang dibuat pada tahun 2003, dan diperbarui pada tahun 2008, kurang 10 tahun perbaikan java yang digunakan oleh solusi seperti hikaricp.

bluejaguar
sumber
4

Seperti yang dijawab oleh orang lain, Anda mungkin akan senang dengan Apache Dbcp atau c3p0 . Keduanya populer, dan berfungsi dengan baik.

Tentang keraguan Anda

Bukankah javax.sql atau java.sql telah menggabungkan implementasi koneksi? Mengapa tidak lebih baik menggunakan ini?

Mereka tidak menyediakan implementasi, melainkan antarmuka dan beberapa kelas dukungan, hanya relevan bagi pemrogram yang mengimplementasikan pustaka pihak ketiga (kumpulan atau driver). Biasanya Anda bahkan tidak melihat itu. Kode Anda harus menangani koneksi dari pool Anda seperti koneksi "biasa", dengan cara yang transparan.

leonbloy.dll
sumber
4

Vibur DBCP adalah perpustakaan lain untuk tujuan itu. Beberapa contoh yang menunjukkan bagaimana mengkonfigurasinya untuk digunakan dengan Hibernate, Spring + Hibernate, atau secara programatik, dapat ditemukan di situsnya: http://www.vibur.org/

Lihat juga penafian di sini .

Simeon Malchev
sumber
3

Apache Commons memiliki perpustakaan untuk tujuan itu: DBCP . Kecuali Anda memiliki persyaratan aneh di sekitar kolam Anda, saya akan menggunakan perpustakaan karena itu pasti lebih rumit dan lebih halus daripada yang Anda harapkan.

sblundy.dll
sumber
1

Anda harus mempertimbangkan untuk menggunakan UCP. Universal Connection Pool (UCP) adalah kolam koneksi Java. Ini adalah kumpulan koneksi yang kaya fitur dan terintegrasi erat dengan database Oracle Real Application Clusters (RAC), ADG, DG.

Lihat halaman ini untuk detail lebih lanjut tentang UCP.

Nirmala
sumber
0

MiniConnectionPoolManager adalah implementasi satu file java, jika Anda mencari solusi yang dapat disematkan dan tidak terlalu peduli dengan kinerja (meskipun saya belum mengujinya dalam hal itu).

Ini adalah EPL multi-lisensi , LGPL dan MPL .

Dokumentasinya juga memberikan alternatif yang layak untuk diperiksa (selain DBCP dan C3P0):

Matthieu
sumber