いままで紹介してきた共有ブックマークの仕組みで、サービスの運用は問題なく行えるようになりました。しかし、いままでのMyDBAccess.classを使用した仕組みでは、データベースへアクセスするたびに毎回コネクションを開き、処理が終わったときにコネクションを閉じることを行っています。
データベースにコネクションを開く処理は、システムに対して比較的負荷のかかる処理であるため、アクセスが多くなってくると、サーバのパフォーマンスに影響を与える可能性があります。そこで、アクセスが多いと想定される場合には、最初にデータベースへのコネクションを複数開き、それを使いまわすことで、毎回コネクションを開かなくてよいような工夫を行います。コネクションをプールする仕組みを作るわけです。
概念としては、下図のように、新しくコネクションプールを管理するMyDBConnectionPoolクラスを作成し、MyDBAccessクラスは、それに対してコネクションを要求し、受け取ったコネクションを使用してデータベースに対する処理を行うことになります。処理を行った後で、使用したコネクションは閉じずに、そのままMyDBConnectionPoolに返却します。MyDBAccessクラスはコネクションの管理は行わず、必要に応じてコネクションプールからコネクションを受け取る処理と返却する処理を行うことになります。コネクションの管理はMyDBConnectionPoolクラスが行います。こうすることで、データベースに対するコネクションの開閉処理によるシステムの負荷を除くことができます。
それでは、実際にコネクションの管理を行うMyDBConnectionPoolクラスを次のように作成してみます。
1: package atmarkit; 2: 3: import java.sql.*; 4: import java.util.Vector; 5: 6: /** 7: * コネクションを保持し管理するクラス 8: */ 9: public class MyDBConnectionPool { 10: 11: // 唯一のインスタンス 12: private static MyDBConnectionPool connectionPool = null; 13: 14: // 同時にデータベースに接続可能なコネクション数 15:private int maxConnection = 5; 16: 17: // コネクションを保持するベクトル 18: private Vector connections = null; 19: 20: // データベースへのアクセスに必要な各値(環境に依存) 21: private String driver = "org.postgresql.Driver"; 22: private String url = "jdbc:postgresql://localhost:5432/bookmarkdb"; 23: private String user = "postgres"; 24: private String password = ""; 25: 26: /** 27: *MyDBConnectionPoolのインスタンスを取得する 28: */ 29: public static MyDBConnectionPool getInstance() throws Exception { 30: if(MyDBConnectionPool.connectionPool == null) { 31: MyDBConnectionPool.connectionPool = new MyDBConnectionPool(); 32: } 33: return MyDBConnectionPool.connectionPool; 34: } 35: 36: /** 37: * インスタンスの生成。privateなので外部からnewで生成はできない。 38: */ 39: private MyDBConnectionPool() throws Exception { 40: Class.forName(driver); 41: connections = new Vector(); 42: for(int i = 0; i < maxConnection; i++) { 43: Connection connection = DriverManager.getConnection(url, user, password); 44: connections.add(connection); 45: } 46: } 47: 48: /** 49: * コネクションを取得する。取得できない場合は引数で与えられた 50: * 回数だけ100ミリ秒おきにトライする。それでも取得できなかった 51: * た場合はnullを返す 52: * @param count 残りの試行回数 53: * @return コネクション 54: */ 55: public synchronized Connection getConnection(int count) { 56: // もし残りの試行回数が1以下だったら null を返す 57: if(count < 1) { 58: return null; 59: } 60: // コネクションが残っていればプールから1つ取り出して提供する 61: if(connections.size() > 0) { 62: Connection connection = (Connection)connections.get(0); 63: connections.remove(0); 64: return connection; 65: } else { // コネクションが残っていなければ100ミリ秒待機 66: try { 67: wait(100); 68: } catch (Exception e) {} 69: // 試行回数を1つ減らして再度取得を実行 70: return getConnection(count-1); 71: } 72: } 73: 74: /** 75: * コネクションを返却する。 76: * 77: * @param connection 返却するコネクション 78: */ 79: public synchronized void releaseConnection(Connection connection){ 80: // プールに返されたコネクションを追加 81: connections.add(connection); 82: } 83: }
ここで紹介するMyDBConnectionPoolは、極めてシンプルなコネクションプールの仕組みを実装しています。まず始めに5つのコネクションを開き、それをVector型のconnectionsに格納し、要求があればそこから1つずつコネクションを提供し、返却があればそこに再び格納します。外部からアクセスできるメソッドは次のとおりです。
メソッド | 戻り値 | 内容 |
---|---|---|
getInstance( ) | MyDBConnectionPool | MyDBConnectionPool のインスタンスを取得します |
getConnection(int count) | Connection | コネクションを取得します。空きコネクションが無い場合、countで指定された回数だけ100ミリ秒の待機を行い、リトライします。取得できなかった場合はnullを返します |
releaseConnection (Connection connection) |
なし | コネクションを返却します |
MyDBConnectionPoolはシングルトンとして定義されていて、インスタンスはただ1つしか生成されないようになっています。外部からnewによるインスタンスの生成は行えません。getInstance()メソッドでインスタンスの取得を行います。
getConnection()メソッドで、コネクションの取得を行います。空きコネクションが残っていない場合には、countで指定された回数だけ100ミリ秒待機し、再度、取得にトライする仕組みになっています。使用したコネクションを返却する際には、releaseConnection(Connection connection)メソッドを使用します。
今回は、簡単なコネクションプールの実装を行っています。より詳しい情報はWeb Developer's Journalの“Improved Performance with a Connection Pool” のコラムが参考になります。
Copyright © ITmedia, Inc. All Rights Reserved.