1. Pendahuluan
Teknologi pengumpulan banyak digunakan di Java. Singkatnya, ia menggunakan kumpulan objek untuk menyimpan instance dengan jumlah instance yang terbatas. Pengembang memperoleh instance dari kumpulan objek dan kemudian beralih kembali ke kumpulan objek setelah digunakan, sehingga mengurangi overhead dari seringnya pembuatan objek dan menghancurkan objek sampai batas tertentu. Pool benang java dan kumpulan koneksi basis data adalah aplikasi yang khas, tetapi tidak semua objek cocok untuk kumpulan. Pooling objek dengan overhead yang relatif kecil akan mempengaruhi kinerja, karena memelihara kumpulan objek juga membutuhkan overhead sumber daya tertentu. Untuk objek dengan overhead tinggi dan seringnya kreasi dan penggunaan penggunaan, menggunakan teknologi pooling akan sangat meningkatkan kinerja.
Ada banyak kumpulan koneksi basis data yang matang di industri, seperti C3P0, DBCP, Proxool dan Druid Alibaba. Ada banyak dan open source, dan Anda dapat menemukan kode sumber di GitHub. Pengembang dapat memilih berdasarkan kebutuhan mereka sendiri dan karakteristik serta kinerjanya. Artikel ini hanya untuk memahami teknologi pengumpulan pembelajaran dan mengimplementasikan kumpulan koneksi basis data sederhana. Jika ada kesalahan, saya berharap dapat mengkritik dan memperbaikinya.
2. Desain
Kelas dan antarmuka utama
.ConnectionParam - Kelas Parameter Pool Koneksi Basis Data, bertanggung jawab untuk mengonfigurasi koneksi database dan parameter terkait kumpulan koneksi. Implementasi Menggunakan Pembangun.
Kata Sandi Pengguna URL Driver - Diperlukan untuk terhubung ke database
MinConnection - Jumlah minimum koneksi
MaxConnection - Jumlah Maksimum Koneksi
Minidle - Jumlah minimum koneksi idle
Maxwait - Waktu tunggu maksimal
pengemudi string final pribadi; URL string final pribadi; Pengguna String Akhir Pribadi; kata sandi string akhir pribadi; Minconnection Int Final Pribadi; private final int maxConnection; minidle int final pribadi; Final Private Long Maxwait;
.Connectionpool - kumpulan koneksi database
Konstruktor ConnectionPool dinyatakan sebagai perlindungan, melarang penciptaan eksternal, dan dikelola secara seragam oleh ConnectionPoolFactory.
ConnectionPool mengimplementasikan metode DataSource dan metode re-getConnection ().
ConnectionPool memegang dua kontainer - satu antrian menyimpan koneksi idle dan vektor lainnya (mempertimbangkan sinkronisasi) menyimpan koneksi yang digunakan.
Ketika pengembang menggunakan koneksi basis data, ia diambil dari antrian, dan jika tidak ada, ia kembali kosong; Ketika koneksi tutup selesai, itu dimasukkan kembali ke vektor.
ConnectionPool menyediakan mekanisme ekspansi dinamis sederhana berdasarkan minidle dan maxConnection.
private static final int initial_size = 5; string final statis privat close_method = "tutup"; Logger Logger Statis Pribadi; ukuran int pribadi; ConnectionParam PrivateParam; private arrayblockingqueue <nection> idleconnectionqueue; vektor pribadi <nection> BusyConnectionVector;
.ConnectionPoolFactory - Kelas Manajemen Kolam Koneksi
ConnectionPoolFactory memegang concurrenthashmap statis untuk menyimpan objek kolam koneksi.
ConnectionPoolFactory memungkinkan membuat beberapa kumpulan koneksi dengan konfigurasi berbeda dari berbagai database.
Pengembang perlu mendaftarkan (mengikat) kumpulan koneksi dengan nama tertentu untuk pertama kalinya, dan kemudian mendapatkan koneksi dari kumpulan koneksi yang ditentukan setiap kali.
Jika kumpulan koneksi tidak lagi digunakan, pengembang dapat keluar (membuka) kumpulan koneksi.
peta statis pribadi <string, connectionPool> poolmap = concurrenthashmap baru <> (); Public Static Connection GetConnection (String PoolName) melempar SQlexception {nameCheck (poolName); ConnectionPool ConnectionPool = poolmap.get (poolname); return connectionPool.getConnection (); } public static void registerConnectionPool (nama string, connectionParam ConnectionParam) {registerCheck (name); poolmap.put (name, connectionPool baru (ConnectionParam)); } // Biarkan GC public static void unregisterConnectionPool (nama string) {nameCheck (name); Final ConnectionPool ConnectionPool = poolmap.get (name); poolmap.remove (nama); utas baru (runnable baru () {@Override public void run () {connectionPool.clear ();}}). start (); }Kode inti
Kode inti kumpulan koneksi database adalah metode getConnection (). Biasanya, setelah pengembang memproses operasi basis data, metode tutup () akan dipanggil. Koneksi harus ditutup dan sumber daya harus dirilis. Di kumpulan koneksi database, ketika pengguna memanggil metode tutup (), koneksi tidak boleh ditutup secara langsung, tetapi harus dimasukkan kembali ke dalam kumpulan dan digunakan kembali. Di sini, mekanisme proxy dinamis Java digunakan. GetConnection mengembalikan bukan koneksi "nyata", tetapi kelas proxy khusus (kelas anonim digunakan di sini). Ketika pengguna memanggil metode tutup (), ia mencegat dan memasukkannya kembali ke kolam. Untuk proxy dinamis, Anda dapat merujuk ke blog lain "Java Dynamic Proxy Simple Application"
@Override Public Connection getConnection () melempar sqlexception {coba {koneksi final connection = idleConnectionqueue.poll (connectionParam.getmaxwait (), timeunit.milliseconds); if (connection == null) {logger.info (emptymsg ()); EnsureCapacity (); kembali nol; } BusyConnectionVector.Add (koneksi); return (connection) proxy.newproxyInstance (this.getClass (). getClassLoader (), kelas baru [] {connection.class}, new InvocateHandler () {@Override Obyek Publik Invoke (Metode Proxy, Metode Metode, Object [] Args) melempar Throwable {if (! Method.getname. args); } catch (InterruptedException e) {E.PrintStackTrace (); } return null; }2. Gunakan
Pertama, pengguna membangun parameter kumpulan koneksi database (ConnectionParam), termasuk driver, URL, pengguna, item yang diperlukan kata sandi. Anda dapat menyesuaikan opsi seperti MinConnection, MaxConnection, dll. Jika tidak diatur, gunakan nilai sistem default. Ini adalah manfaat menggunakan pembangun untuk membangun sejumlah besar atribut, termasuk atribut yang diperlukan dan atribut opsional. Kemudian daftarkan kumpulan koneksi dengan ConnectionPoolFactory dengan nama tertentu, dan akhirnya dapatkan koneksi dengan memanggil metode Factory Statis ConnectionPoolFactory.
String driver = "com.mysql.jdbc.driver"; String url = "jdbc: mysql: // localhost: 3306/test"; String user = "root"; String password = "root"; ConnectionParam ConnectionParam = new ConnectionParam.ConnectionParambuilder (driver, URL, pengguna, kata sandi) .build (); ConnectionPoolFactory.RegisterConnectionPool ("Test", ConnectionParam); Koneksi koneksi = ConnectionPoolFactory.getConnection ("test");3. Kode
.ParamConfiguration
Paket database.config; impor java.io.serializable;/** * Parameter koneksi basis data * dibuat oleh Michael Wong pada 2016/1/18. */kelas publik ParamConfiguration mengimplementasikan serializable {public static final int min_connection = 5; final public static int max_connection = 50; final public static int min_idle = 5; final public static long max_wait = 30000; private paramConfiguration () {}}.Pembangun
Paket database;/** * pembangun * dibuat oleh Michael Wong pada 2016/1/18. */pembangun antarmuka publik <T> {t build ();}.ConnectionParam
Paket database; impor database.config.paramconfiguration;/** * Parameter koneksi database * Dibuat oleh Michael Wong pada 2016/1/18. */Connection Public ConnectionParam {Private Final String Driver; URL string final pribadi; Pengguna String Akhir Pribadi; kata sandi string akhir pribadi; Minconnection Int Final Pribadi; private final int maxConnection; minidle int final pribadi; Final Private Long Maxwait; Private ConnectionParam (ConnectionParambuilder Builder) {this.driver = builder.driver; this.url = builder.url; this.user = builder.user; this.password = builder.password; this.minconnection = builder.minconnection; this.maxConnection = builder.maxConnection; this.minidle = builder.minidle; this.maxwait = builder.maxwait; } public String getDriver () {return this.driver; } public String getUrl () {return this.url; } public string getUser () {return this.user; } public String getPassword () {return this.password; } public int getMinconnection () {return this.minconnection; } public int getMaxConnection () {return this.maxConnection; } public int getminidle () {return this.minidle; } public long getmaxwait () {return this.maxwait; } public static class connectionParambuilder mengimplementasikan builder <nectionParam> {// Parameter yang Diperlukan Driver String Akhir Pribadi; URL string final pribadi; Pengguna String Akhir Pribadi; kata sandi string akhir pribadi; // Parameter Opsional - Diinisialisasi ke Nilai Default Private Int MinConnection = ParamConfiguration.min_connection; private int maxConnection = paramConfiguration.max_connection; private int minidle = paramconfiguration.min_idle; // mendapatkan waktu tunggu waktu tunggu pribadi long maxwait = paramconfiguration.max_wait; Public ConnectionParambuilder (String Driver, String URL, String User, String Password) {this.Driver = driver; this.url = url; this.user = pengguna; this.password = kata sandi; } public ConnectionParambuilder MinConnection (int MinConnection) {this.minconnection = MinConnection; kembalikan ini; } public ConnectionParambuilder maxConnection (int maxConnection) {this.maxConnection = maxConnection; kembalikan ini; } public ConnectionParambuilder minidle (int minidle) {this.minidle = minidle; kembalikan ini; } public ConnectionParambuilder maxwait (int maxwait) {this.maxwait = maxwait; kembalikan ini; } @Override Public ConnectionParam build () {return new ConnectionParam (this); }}}.Connectionpool
Paket database.Factory; impor database.connectionParam; import javax.sql.datasource; impor java.io.printwriter; impor java.lang.reflect.invocationHandler; impor Java.lang.reflect.method; impor java.lang.reflen. java.sql.driverManager; impor java.sql.sqlexception; impor java.sql.sqlfeatureNotsupportedException; java.util.vector; import java.util.concurrent.arrAnTeunqueue; impor java.util.util.concurrent. java.util.logging.logger;/** * Pool koneksi * Dibuat oleh Michael Wong pada 2016/1/18. */Public Class ConnectionPool mengimplementasikan DataSource {private static int int initial_size = 5; string final statis privat close_method = "tutup"; Logger Logger Statis Pribadi; ukuran int pribadi; ConnectionParam PrivateParam; private arrayblockingqueue <nection> idleconnectionqueue; vektor pribadi <nection> BusyConnectionVector; Protected ConnectionPool (ConnectionParam ConnectionParam) {this.connectionParam = ConnectionParam; int maxConnection = connectionParam.getmaxConnection (); idleConnectionQueUe = arrayblockingqueue baru <> (maxConnection); BusyConnectionVector = vektor baru <> (); logger = logger.getLogger (this.getClass (). getName ()); initConnection (); } private void initConnection () {int MinConnection = connectionParam.getMinconnection (); int initialsize = initial_size <MinConnection? MinConnection: initial_size; coba {class.forname (ConnectionParam.getDriver ()); untuk (int i = 0; i <initialize+connectionParam.getMinconnection (); i ++) {idleConnectionqueue.put (newConnection ()); ukuran ++; }} catch (exception e) {lempar pengecualian baruininitialierererRor (e); }} @Override Public Connection getConnection () melempar sqlexception {try {final connection connection = idleConnectionqueue.poll (connectionParam.getmaxwait (), timeunit.milliseconds); if (connection == null) {logger.info (emptymsg ()); EnsureCapacity (); kembali nol; } BusyConnectionVector.Add (koneksi); return (connection) proxy.newproxyInstance (this.getClass (). getClassLoader (), kelas baru [] {connection.class}, new InvocateHandler () {@Override Obyek Publik Invoke (Metode Proxy, Metode Metode, Object [] Args) melempar Throwable {if (! Method.getname. args); } catch (InterruptedException e) {E.PrintStackTrace (); } return null; } private connection newConnection () melempar sqlexception {string url = connectionParam.getUrl (); String user = connectionParam.getUser (); String password = connectionParam.getPassword (); return driverManager.getConnection (url, pengguna, kata sandi); } ukuran int terlindungi () {ukuran pengembalian; } protected int idLeConnectionQuantity () {return idleConnectionQueUe.size (); } protected int BusyConnectionQuantity () {return BusyConnectionVector.size (); } private void ensureCapacity () melempar sqlexception {int minidle = connectionParam.getMinidle (); int maxConnection = connectionParam.getmaxConnection (); int newcapacity = size + minidle; newCapacity = newCapacity> maxConnection? MaxConnection: Newcapacity; int growcount = 0; if (size <newCapacity) {coba {for (int i = 0; i <newCapacity - size; i ++) {idleConnectionqueue.put (newConnection ()); growcount ++; }} catch (InterruptedException e) {E.PrintStackTrace (); }} size = size + growcount; } protected void clear () {coba {while (size--> 0) {koneksi koneksi = idleConnectionqueue.take (); koneksi.close (); }} catch (InterruptedException | SQlexception e) {E.PrintStackTrace (); }} basis data string pribadi () {return "sibuk, tunggu ..."; } @Override Public Connection getConnection (string username, string password) melempar sqlexception {return null; } @Override public printwriter getLogWriter () melempar sqlexception {return null; } @Override public void setLogWriter (printwriter out) melempar sqlexception {} @override public void setLogInmeout (int detik) melempar sqlexception {} @Override int getLogInimeout () melempar sqlexception {return 0; } @Override Public Logger getParentLogger () melempar sqlfeaturenotsupportedException {return null; } @Override public <t> t unwrap (class <t> iface) melempar sqlexception {return null; } @Override public boolean isWrapperfor (class <?> Iface) melempar sqlexception {return false; }}.ConnectionPoolFactory
package database.factory;import database.ConnectionParam;import java.sql.Connection;import java.sql.SQLException;import java.util.Map;import java.util.concurrent.ConcurrentHashMap;/** * Connection Pool Factory * Created by Michael Wong on 2016/1/18. */Public Class ConnectionPoolFactory {private connectionPoolFactory () {} private static Map <String, ConnectionPool> poolmap = concurrenthashMap baru <> (); Public Static Connection GetConnection (String PoolName) melempar SQlexception {nameCheck (poolName); ConnectionPool ConnectionPool = poolmap.get (poolname); return connectionPool.getConnection (); } public static void registerConnectionPool (nama string, connectionParam ConnectionParam) {registerCheck (name); poolmap.put (name, connectionPool baru (ConnectionParam)); } // Biarkan GC public static void unregisterConnectionPool (nama string) {nameCheck (name); Final ConnectionPool ConnectionPool = poolmap.get (name); poolmap.remove (nama); utas baru (runnable baru () {@Override public void run () {connectionPool.clear ();}}). start (); } public static int size (string poolName) {nameCheck (poolname); return poolmap.get (poolname) .size (); } public static int getIdleConnectionQuantity (string poolName) {nameCheck (poolname); return poolmap.get (poolname) .idleConnectionQuantity (); } public static int getBusyConnectionQuantity (string poolname) {nameCheck (poolname); return poolmap.get (poolname) .busyConnectionQuantity (); } private static void registerCheck (name string) {if (name == null) {lempar new IllegalArgumentException (nullName ()); }} private static void nameCheck (nama string) {if (name == null) {lempar baru ilegalArgumentException (nullName ()); } if (! poolmap.containskey (name)) {lempar baru ilegalargumentException (notexists (name)); }} private static string nullName () {return "name pool tidak boleh null"; } private static string notexists (string name) {return "connection pool bernama" + name + "tidak ada"; }} 4. Tes
Pengujian unit junit
Paket database.factory; impor database.connectionparam; impor org.junit.test; impor java.sql.connection; impor java.sql.sqlexception; impor java.util.raylist; import* *util.list; impor org.util ongoulser*; 2016/1/20. */Public Class ConnectionPoolFactoryTest {@test public void testGetConnection () melempar sqlexception {string driver = "com.mysql.jdbc.driver"; String url = "jdbc: mysql: // localhost: 3306/test"; String user = "root"; String password = "root"; ConnectionParam ConnectionParam = new ConnectionParam.ConnectionParambuilder (driver, URL, pengguna, kata sandi) .build (); ConnectionPoolFactory.RegisterConnectionPool ("Test", ConnectionParam); Daftar <nection> ConnectionList = ArrayList baru <> (); untuk (int i = 0; i <12; i ++) {ConnectionList.Add (ConnectionPoolFactory.getConnection ("test")); } print (); tutup (ConnectionList); mencetak(); ConnectionList.Clear (); untuk (int i = 0; i <12; i ++) {ConnectionList.Add (ConnectionPoolFactory.getConnection ("test")); } print (); tutup (ConnectionList); ConnectionPoolFactory.UnRegisterConnectionPool ("Test"); } @Test (diharapkan = IllegalArgumentException.class) public void testException () {coba {connectionPoolFactory.getConnection ("test"); } catch (sqlexception e) {e.printstacktrace (); }} private void tutup (daftar <nection> ConnectionList) melempar sqlexception {for (koneksi conn: connectionList) {if (conn! = null) {conn.close (); }}} private void print () {System.out.println ("idle:" + connectionPoolFactory.getIdleConnectionQuantity ("test")); System.out.println ("Sibuk:" + ConnectionPoolFactory.getBusyConnectionQuantity ("Test")); System.out.println ("Size:" + ConnectionPoolFactory.size ("Test")); }}Di atas adalah semua tentang artikel ini, saya harap ini akan membantu untuk pembelajaran semua orang.