1。はじめに
プーリングテクノロジーは、Javaで広く使用されています。要するに、オブジェクトプールを使用して、インスタンスの数が限られているインスタンスを保存します。開発者はオブジェクトプールからインスタンスを取得し、使用後にオブジェクトプールに戻し、システムのオブジェクトの頻繁な作成とオブジェクトをある程度破壊するオーバーヘッドを減らします。 Javaスレッドプールとデータベース接続プールは典型的なアプリケーションですが、すべてのオブジェクトがプールに適しているわけではありません。オブジェクトプールを維持するには特定のリソースのオーバーヘッドが必要であるため、比較的小さなオーバーヘッドを持つオブジェクトをプールすることはパフォーマンスに影響します。オーバーヘッドが高く、頻繁に使用され、使用が使用されるオブジェクトの場合、プーリングテクノロジーを使用すると、パフォーマンスが大幅に向上します。
C3P0、DBCP、Proxool、Alibabaのドルイドなど、業界には多くの成熟したデータベース接続プールがあります。多くのオープンソースがあり、GitHubにソースコードを見つけることができます。開発者は、自分のニーズと特性とパフォーマンスに基づいて選択できます。この記事は、学習プーリングテクノロジーを理解し、簡単なデータベース接続プールを実装するためだけです。エラーがある場合は、それらを批判し、修正したいと考えています。
2。デザイン
メインクラスとインターフェイス
.ConnectionParam-データベース接続プールパラメータークラス。データベース接続と接続プール関連のパラメーターの構成を担当します。ビルダーを使用した実装。
ドライバーURLユーザーパスワード - データベースに接続するために必要
MinConnection-接続の最小数
MaxConnection-接続の最大数
Minidle-アイドル接続の最小数
MaxWait-最大待機時間
プライベートファイナルストリングドライバー。プライベート最終文字列URL;プライベートファイナルストリングユーザー。プライベート最終文字列パスワード。プライベートファイナルイントミンコネクション。プライベートファイナルイントマックスコネクション。プライベートファイナルイントミニドル。プライベートファイナルロングマックスウェイト。
.ConnectionPool-データベース接続プール
ConnectionPoolコンストラクターは保護として宣言され、外部作成を禁止し、ConnectionPoolFactoryによって均一に管理されます。
ConnectionPoolは、DataSourceインターフェイスとRegetConnection()メソッドを実装します。
ConnectionPoolは2つのコンテナを保持しています - 1つのキューがアイドル接続を保存し、もう1つのベクトル(同期を考慮して)を使用して保存します。
開発者がデータベース接続を使用すると、キューから取得され、noがある場合は空に戻ります。接続が完了すると、ベクトルに戻されます。
ConnectionPoolは、MinidleとMaxConnectionに基づいた単純な動的拡張メカニズムを提供します。
プライベート静的最終int initial_size = 5; private static final string close_method = "close";プライベート静的ロガーロガー。プライベートINTサイズ。 Private ConnectionParam ConnectionParam; private arrayblockingqueue <connection> idleconnectionqueue; private vector <connection> busyconnectionvector;
.ConnectionPoolFactory-接続プール管理クラス
ConnectionPoolFactoryは、接続プールオブジェクトを保存するための静的な同時ハッシュマップを保持します。
ConnectionPoolFactoryを使用すると、異なるデータベースの異なる構成で複数の接続プールを作成できます。
開発者は、接続プールを初めて特定の名前で登録(バインド)し、毎回指定された接続プールから接続を取得する必要があります。
接続プールが使用されなくなった場合、開発者は接続プールにログアウト(バインド)できます。
private static map <string、connectionpool> poolmap = new concurrenthashmap <>(); public static Connection getConnection(String PoolName)STHOWS SQLEXCEPTION {NAMECHECK(PoolName); ConnectionPool ConnectionPool = poolmap.get(poolname); connectionPool.getConnection()を返します。 } public static void RegisterConnectionPool(String name、ConnectionParam ConnectionParam){RegisterCheck(name); poolmap.put(name、new ConnectionPool(ConnectionParam)); } // gc public static void unregisterconnectionpool(string name){namecheck(name); final ConnectionPool connectionpool = poolmap.get(name); poolmap.remove(name);新しいスレッド(new runnable(){@override public void run(){connectionpool.clear();}})。start(); }コアコード
データベース接続プールのコアコードは、getConnection()メソッドです。通常、開発者がデータベース操作を処理した後、close()メソッドが呼び出されます。接続を閉じ、リソースをリリースする必要があります。データベース接続プールでは、ユーザーがclose()メソッドを呼び出す場合、接続を直接閉じてはいけませんが、プールに戻して再利用する必要があります。ここでは、Javaダイナミックプロキシメカニズムが使用されます。 getConnectionは「実際の」接続ではなく、カスタムプロキシクラスを返します(匿名クラスはここで使用されます)。ユーザーがclose()メソッドを呼び出すと、それを傍受してプールに戻します。動的プロキシについては、別のブログ「Java Dynamic Proxy Simple Application」を参照できます。
@Override public connection getConnection()throws sqlexception {try {final connection = idleconnectionqueue.poll(connectionParam.getMaxWait()、TimeUnit.milliseConds); if(connection == null){logger.info(emptymsg()); EnsureCapacity(); nullを返します。 } busyconnectionvector.add(connection); return(connection)proxy.newproxyinstance(this.getClass()。getClassLoader()、new class [] {connection.class}、new rideRide public handler(){@Override public object(オブジェクトプロキシ、メソッドメソッド、オブジェクト[] args)スロー可能{if(!method.getName() args) } catch(arturnedexception e){e.printstacktrace(); } nullを返します。 }2。使用します
まず、ユーザーは、ドライバー、URL、ユーザー、必要なアイテムを含むデータベース接続プールパラメーター(ConnectionParam)を構築します。 Minconnection、MaxConnectionなどのオプションをカスタマイズできます。設定していない場合は、システムのデフォルト値を使用します。これは、ビルダーを使用して、必要な属性やオプションの属性を含む多数の属性を構築することの利点です。次に、ConnectionPoolFactoryを特定の名前で接続プールを登録し、ConnectionPoolFactory Static Factoryメソッドを呼び出して接続を取得します。
string driver = "com.mysql.jdbc.driver"; string url = "jdbc:mysql:// localhost:3306/test";文字列ユーザー= "root";文字列パスワード= "root"; ConnectionParam ConnectionParam = new ConnectionParam.ConnectionParamBuilder(ドライバー、URL、ユーザー、パスワード).Build(); ConnectionPoolFactory.registerConnectionPool( "TEST"、ConnectionParam); Connection Connection = ConnectionPoolFactory.GetConnection( "TEST");
3。コード
.ParamConfiguration
パッケージdatabase.config; Import java.io.serializable;/** *データベース接続パラメーター * 2016/1/18にMichael Wongによって作成されました。 */public class paramconfigurationはシリアル化可能{public static final int min_connection = 5; public static final int max_connection = 50; public static final int min_idle = 5; public static final long max_wait = 30000; private paramconfiguration(){}}。ビルダー
パッケージデータベース;/** * Builder * 2016/1/18にMichael Wongが作成しました。 */public interface builder <t> {t build();}.ConnectionParam
パッケージデータベース; Import database.config.paramconfiguration;/** *データベース接続パラメーター * 2016/1/18にMichael Wongが作成しました。 */public class ConnectionParam {プライベートファイナルストリングドライバー。プライベート最終文字列URL;プライベートファイナルストリングユーザー。プライベート最終文字列パスワード。プライベートファイナルイントミンコネクション。プライベートファイナルイントマックスコネクション。プライベートファイナルイントミニドル。プライベートファイナルロングマックスウェイト。 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を実装します。プライベート最終文字列URL;プライベートファイナルストリングユーザー。プライベート最終文字列パスワード。 //オプションパラメーター - デフォルトに初期化されたプライベートint minconnection = paramconfiguration.min_connection; private int maxconnection = paramconfiguration.max_connection; private int minidle = paramconfiguration.min_idle; //接続の取得待機時間プライベート長いmaxwait = paramconfiguration.max_wait; public ConnectionParamBuilder(String Driver、String URL、String User、String Password){this.driver = driver; this.url = url; this.user = user; this.password = password; } public ConnectionParamBuilder Minconnection(int minconnection){this.minconnection = minconnection;これを返します。 } public ConnectionParambuilder maxconnection(int maxconnection){this.maxconnection = maxconnection;これを返します。 } public ConnectionParambuilder Minidle(int minidle){this.minidle = minidle;これを返します。 } public ConnectionParambuilder MaxWait(int maxwait){this.maxwait = maxwait;これを返します。 } @Override public ConnectionParam build(){return new ConnectionParam(this); }}}.ConnectionPool
パッケージデータベース.Factory; Import database.connectionParam; Import javax.sql.datasource; Import java.io.printwriter; Import java.lang.Leflt.InvocationHandler; Import java.lang.reflect.method; java.sql.drivermanager; Import java.sql.sqlexception; Import java.sql.sql.sql.sql.featurenotsupportedexception; Import java.util.vector; Import java.util.concurrent.ArrayblockingQueue; Import Java.util.concurrent; Import; Java.util.logging.logger;/** *接続プール * 2016/1/18にMichael Wongが作成しました。 */public class connectionpoolはdataSource {private static final int initial_size = 5; private static final string close_method = "close";プライベート静的ロガーロガー。プライベートINTサイズ。 Private ConnectionParam ConnectionParam; private arrayblockingqueue <connection> idleconnectionqueue; private vector <connection> busyconnectionvector; Protected ConnectionPool(ConnectionParam ConnectionParam){this.connectionParam = connectionParam; int maxconnection = connectionParam.getMaxConnection(); idleconnectionQueue = new arrayblockingqueue <>(maxconnection); busyconnectionvector = new Vector <>(); logger = logger.getLogger(this.getClass()。getName()); initConnection(); } private void initconnection(){int minconnection = connectionParam.getMinconnection(); int Intialsize = initial_size <minconnection? minconnection:initial_size; try {class.forname(connectionParam.getDriver()); for(int i = 0; i <hirtingsize+connectionParam.getMinconnection(); i ++){idleconnectionQueue.put(newConnection());サイズ++; }} catch(Exception e){新しい例外InchinitializerError(e); }} @Override public Connection getConnection()throws sqlexception {try {final connection = idleconnectionqueue.poll(connectionParam.getMaxWait()、TimeUnit.MilliseConds); if(connection == null){logger.info(emptymsg()); EnsureCapacity(); nullを返します。 } busyconnectionvector.add(connection); return(connection)proxy.newproxyinstance(this.getClass()。getClassLoader()、new class [] {connection.class}、new rideRide public handler(){@Override public object(オブジェクトプロキシ、メソッドメソッド、オブジェクト[] args)スロー可能{if(!method.getName() args) } catch(arturnedexception e){e.printstacktrace(); } nullを返します。 } private connection newConnection()throws sqlexception {string url = connectionParam.geturl(); string user = connectionParam.getUser();文字列パスワード= ConnectionParam.getPassWord(); drivermanager.getConnection(url、user、password)を返します。 } protected int size(){return size; } protected int idleconnectionquantity(){return idleconnectionqueue.size(); }保護されたint busyconnectionquantity(){return busyconnectionvector.size(); } private void ensurecapacity()throws sqlexception {int minidle = connectionParam.getMinidle(); int maxconnection = connectionParam.getMaxConnection(); int newcapacity = size + minidle; newcapacity = newcapacity> maxconnection? maxconnection:newcapacity; int growcount = 0; if(size <newcapacity){try {for(int i = 0; i <newcapacity -size; i ++){idleconnectionqueue.put(newConnection()); GrowCount ++; }} catch(arturnedexception e){e.printstacktrace(); }} size = size + growcount; } protected void clear(){try {while(size-> 0){connection connection = idleconnectionqueue.take(); connection.close(); }} catch(arturnedexception | sqlexception e){e.printstacktrace(); }} private string emptymsg(){return "データベースはビジーです、待ってください..."; } @Override public Connection getConnection(string username、string password)throws sqlexception {return null; } @Override printWriter getLogWriter()throws sqlexception {return null; } @Override public void setlogwriter(printwriter out)throws sqlexception {} @override public void setLogIntimeout(int sconeds)throws sqlexception {} @override public int getlogintimeout()throws sqlexception {return 0; } @Override public logger getParentLogger()throws sqlfeaturenotsupportedexception {return null; } @override public <t> t Unwrap(class <t> iface)throws sqlexception {return null; } @Override public boolean iswrapperfor(class <?> iface)throws sqlexception {return false; }}.ConnectionPoolFactory
Package.factory; Import database.connectionParam;インポートjava.sql.connection; Import java.sql.sqlexception; Import java.util.map; Import java.util.concurrent.concurrenthashmap;/** *接続プールファクトリ *は2016/1/18でMichale Wongによって作成されました。 */public class ConnectionPoolFactory {private connectionPoolFactory(){} private static Map <string、connectionPool> poolmap = new concurrenthashmap <>(); public static Connection getConnection(String PoolName)STHOWS SQLEXCEPTION {NAMECHECK(PoolName); ConnectionPool ConnectionPool = poolmap.get(poolname); connectionPool.getConnection()を返します。 } public static void RegisterConnectionPool(String name、ConnectionParam ConnectionParam){RegisterCheck(name); poolmap.put(name、new ConnectionPool(ConnectionParam)); } // gc public static void unregisterconnectionpool(string name){namecheck(name); final ConnectionPool connectionpool = poolmap.get(name); poolmap.remove(name);新しいスレッド(new runnable(){@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(String name){if(name == null){throw new IllegalArgumentException(nullName()); }} private static void namecheck(string name){if(name == null){throw new IllegalArgumentException(nullName()); } if(!poolmap.containskey(name)){新しいIllegalargumentException(notexists(name)); }} private static string nullname(){return "プール名はnullではない"; } private static string notexists(string name){return "connection pool not +"は存在しません "; }} 4。テスト
JUNITユニットテスト
Package database.factory; Import database.connectionParam; Import org.junit.test; Import java.sql.connection; Import java.sqlexception; Import java.util.laylist; import java.util.list; Import static org.junit。 2016/1/20。 */public class ConnectionPoolFactoryTest {@Test public void testgetConnection()throws sqlexception {string driver = "com.mysql.jdbc.driver"; string url = "jdbc:mysql:// localhost:3306/test";文字列ユーザー= "root";文字列パスワード= "root"; ConnectionParam ConnectionParam = new ConnectionParam.ConnectionParamBuilder(ドライバー、URL、ユーザー、パスワード).Build(); ConnectionPoolFactory.registerConnectionPool( "TEST"、ConnectionParam);リスト<connection> connectionlist = new ArrayList <>(); for(int i = 0; i <12; i ++){connectionlist.add(connectionPoolFactory.getConnection( "test")); } print(); close(connectionlist); print(); ConnectionList.Clear(); for(int i = 0; i <12; i ++){connectionlist.add(connectionPoolFactory.getConnection( "test")); } print(); close(connectionlist); ConnectionPoolFactory.UnregisterConnectionPool( "TEST"); } @test(expection = IllegalargumentException.class)public void testexception(){try {connectionPoolFactory.getConnection( "test"); } catch(sqlexception e){e.printstacktrace(); }} private void close(list <connection> connectionlist)throws sqlexception {for(connection conn:connectionlist){if(conn!= null){conn.close(); }}} private void print(){system.out.println( "idle:" + connectionPoolFactory.GetIdLeconnectionQuantity( "test")); system.out.println( "Bushed:" + connectionPoolFactory.getBusyConnectionQuantity( "test")); system.out.println( "size:" + connectionPoolFactory.size( "test")); }}上記はこの記事に関するものです。すべての人の学習に役立つことを願っています。