Java Database Connectivity(JDBC)Oracle Call Interface(OCI)ドライバ接続プーリング機能は、JDBCクライアントの一部です。この機能は、OracleOCIConnectionPool
クラスによって提供されます。
JDBCアプリケーションでは、同時に複数のプールを保持できます。複数のプールを保持すると、複数のアプリケーション・サーバーや異なるデータソースの各プールに対応できます。JDBC OCIドライバで提供される接続プーリングでは、アプリケーションで少数の物理接続をすべて使用して、複数の論理接続を保持できます。この論理接続でのコールは、コールの時点で使用可能な物理接続にルーティングされます。
この章では、次の項目について説明します。
注意: セッションの多重化が必要な場合は、OCI接続を使用してください。OCI接続を使用しない場合は、暗黙的接続キャッシュを使用することをお薦めします。 |
Oracle JDBC OCIドライバは、Oracleセッションおよび接続の細かな管理などのいくつかのトランザクション・モニター機能を提供します。ハイエンド・アプリケーション・サーバーまたはトランザクション・モニターでは、コール・レベルで少数の物理接続を通じて、複数のセッションを多重化できるため、接続とバックエンドのOracleサーバー・プロセスをプーリングすることで、高度な拡張性を実現できます。
OracleOCIConnectionPool
インタフェースによって提供される接続プーリングでは、物理接続プールの管理を隠すことでセッション/接続の分割インタフェースが簡素化されます。Oracleセッションは、OracleOCIConnectionPool
から取得されるOracleOCIConnection
オブジェクトです。通常、接続プールそのものは、さらに少ない物理接続の共有プールで構成されます。これは同じ数の専用サーバー・プロセスを含むバックエンド・サーバー・プールになります。この少数の共有接続とバックエンドOracleプロセスのプールにより、もっと多くのOracleセッションを多重化することができます。
ある意味では、OCIドライバ接続プーリングが中間層で提供する機能は、共有サーバー・プロセスがバックエンドで提供する機能と同じです。OCIドライバ接続プーリングでは、中間層でセッションの多重化ロジックを管理することで、専用サーバー・インスタンスが共有インスタンスと同じように動作します。したがって、専用サーバー・プロセスと専用サーバー・プロセスへの接続のプーリングは、中間層にあるOCI接続プールで制御されます。
OCI接続プーリングと共有サーバーの主な違いは、共有サーバーを使用する場合、通常はデータベース・インスタンス内のディスパッチャに対してクライアントから接続が行われることです。ディスパッチャは、クライアントからの要求を適切な共有サーバーにリダイレクトします。他方、OCI接続プールからの物理接続は、バックエンド・サーバー・プールにあるOracle専用サーバー・プロセスに対して中間層から直接確立されます。
OCI接続プールが有効なのは、中間層がマルチスレッドである場合のみです。各スレッドは、データベースに対して1つのセッションを保持できます。データベースに対する実際の接続は、OracleOCIConnectionPool
によって保持され、これらの接続は、専用データベース・サーバー・プロセスのプールも含めて、中間層のすべてのスレッドで共有されます。
OCI接続プールは、アプリケーションの開始時に作成されます。プールから接続を作成する方法は、OracleDataSource
クラスを使用して接続を作成する方法とほぼ同じです。
OCI接続プールの作成には、OracleDataSource
クラスを拡張するoracle.jdbc.pool.OracleOCIConnectionPool
クラスを使用します。OracleOCIConnectionPool
インスタンスから、論理接続オブジェクトを取得できます。これらの接続オブジェクトは、OracleOCIConnection
クラス型です。このクラスは、OracleConnection
インタフェースを実装します。OracleOCIConnection
インスタンスから作成したStatement
オブジェクトには、OracleConnection
インスタンスから作成したOracleStatement
オブジェクトと同じフィールドおよびメソッドがあります。
次のコードは、OracleOCIConnectionPool
クラスのヘッダー情報を示します。
/* * @param us ConnectionPool user-id. * @param p ConnectionPool password * @param name logical name of the pool. This needs to be one in the * tnsnames.ora configuration file. @param config (optional) Properties of the pool, if the default does not suffice. Default connection configuration is min =1, max=1, incr=0 Please refer setPoolConfig for property names. Since this is optional, pass null if the default configuration suffices. * @return * * Notes: Choose a userid and password that can act as proxy for the users * in the getProxyConnection() method. If config is null, then the following default values will take effect CONNPOOL_MIN_LIMIT = 1 CONNPOOL_MAX_LIMIT = 1 CONNPOOL_INCREMENT = 0 */ public synchronized OracleOCIConnectionPool (String user, String password, String name, Properties config) throws SQLException /* * This will use the user-id, password and connection pool name values set LATER using the methods setUser, setPassword, setConnectionPoolName. * @return * * Notes: No OracleOCIConnection objects can be created on this class unless the methods setUser, setPassword, setPoolConfig are invoked. When invoking the setUser, setPassword later, choose a userid and password that can act as proxy for the users * in the getProxyConnection() method. */ public synchronized OracleOCIConnectionPool () throws SQLException
oracle.jdbc.poolパッケージおよびoracle.jdbc.ociパッケージのインポート
OCI接続プールを作成する前に、Oracle OCI接続プーリング機能に次のパッケージをインポートする必要があります。
import oracle.jdbc.pool.*; import oracle.jdbc.oci.*;
OCI接続プールの作成
次のコードは、cpool
という名前のOracleOCIConnectionPool
クラスのインスタンスを作成する方法を示します。
OracleOCIConnectionPool cpool = new OracleOCIConnectionPool ("SCOTT", "TIGER", "jdbc:oracle:oci:@(description=(address=(host= myhost)(protocol=tcp)(port=1521))(connect_data=(INSTANCE_NAME=orcl)))", poolConfig);
poolConfig
は、接続プールを指定する一連のプロパティです。poolConfig
がNULLの場合は、デフォルト値が使用されます。たとえば、次の場合を考えてみましょう。
poolConfig.put (OracleOCIConnectionPool.CONNPOOL_MIN_LIMIT, "4");
poolConfig.put (OracleOCIConnectionPool.CONNPOOL_MAX_LIMIT, "10");
poolConfig.put (OracleOCIConnectionPool.CONNPOOL_INCREMENT, "2");
コンストラクタ・コール以外にも、個々のメソッドを使用してユーザー、パスワードおよび接続文字列を指定して、OracleOCIConnectionPool
クラスのインスタンスを作成する方法もあります。
OracleOCIConnectionPool cpool = new OracleOCIConnectionPool ( ); cpool.setUser("SCOTT"); cpool.setPassword("TIGER"); cpool.setURL("jdbc:oracle:oci:@(description=(address=(host= myhost)(protocol=tcp)(port=1521))(connect_data=(INSTANCE_NAME=orcl)))"); cpool.setPoolConfig(poolConfig); // In case you want to specify a different // configuration other than the default // values.
OCI接続プール・パラメータの設定
接続プールの構成は、次に示すOracleOCIConnectionPool
クラス属性によって決まります。
CONNPOOL_MIN_LIMIT
プールで保持できる物理接続の最小数を指定します。
CONNPOOL_MAX_LIMIT
プールで保持できる物理接続の最大数を指定します。
CONNPOOL_INCREMENT
既存の接続がすべて使用中で、さらに接続が必要になったとき、オープンする物理接続の増分数を指定します。オープンしている物理接続の数が、そのプールについてオープンできる接続の最大数を超えない場合にのみ、接続がオープンされます。
CONNPOOL_TIMEOUT
物理接続が切断されるまでのアイドル状態の時間を指定します。これは論理接続には影響しません。
CONNPOOL_NOWAIT
この属性を有効に設定すると、プール内の最大数の接続が使用されている場合に、コールに物理接続が必要になるとエラーが返されます。この属性を無効に設定すると、接続が使用可能になるまでコールは待機します。この属性をtrue
に設定した後で、false
にリセットすることはできません。
これらの属性はすべて動的に構成できます。したがって、アプリケーションではカレント・ロード、つまりオープンしている接続の数と使用中の接続の数を読み取って、setPoolConfig
メソッドを使用してこれらの属性を適切に調整できます。
注意: CONNPOOL_MIN_LIMIT 、CONNPOOL_MAX_LIMIT およびCONNPOOL_INCREMENT パラメータのデフォルト値は、それぞれ1 、1 および0 です。 |
OCI接続プールのプロパティを構成するには、setPoolConfig
メソッドを使用します。次は、OracleOCIConnectionPool
クラス属性の代表的な設定例です。
... java.util.Properties p = new java.util.Properties( ); p.put (OracleOCIConnectionPool.CONNPOOL_MIN_LIMIT, "1"); p.put (OracleOCIConnectionPool.CONNPOOL_MAX_LIMIT, "5"); p.put (OracleOCIConnectionPool.CONNPOOL_INCREMENT, "2"); p.put (OracleOCIConnectionPool.CONNPOOL_TIMEOUT, "10"); p.put (OracleOCIConnectionPool.CONNPOOL_NOWAIT, "true"); cpool.setPoolConfig(p); ...
これらの属性を設定するときは、次の規則に従ってください。
CONNPOOL_MIN_LIMIT
、CONNPOOL_MAX_LIMIT
およびCONNPOOL_INCREMENT
パラメータは必須です。
CONNPOOL_MIN_LIMIT
の値はゼロより大きくしてください。
CONNPOOL_MAX_LIMIT
は、CONNPOOL_MIN_LIMIT
とCONNPOOL_INCREMENT
を足した値以上にしてください。
CONNPOOL_INCREMENT
の値はゼロ以上にしてください。
CONNPOOL_TIMEOUT
の値はゼロより大きくしてください。
CONNPOOL_NOWAIT
は、true
またはfalse
にしてください。
関連項目: 『Oracle Call Interfaceプログラマーズ・ガイド』 |
OCI接続プール・ステータスのチェック
接続プールのステータスをチェックするには、OracleOCIConnectionPool
クラスの次のメソッドを使用します。
int getMinLimit()
プールで保持できる物理接続の最小数を取得します。
int getMaxLimit()
プールで保持できる物理接続の最大数を取得します。
int getConnectionIncrement()
既存の接続がすべて使用中に、コールに接続が必要になったときにオープンする物理接続の増分数を取得します。
int getTimeout()
プールの物理接続が切断されるまでのアイドル状態の時間(秒単位)を取得します。接続の持続時間は最低使用頻度(LRU)アルゴリズムに基づいて決定されます。
String getNoWait()
NOWAIT
プロパティが有効かどうかを取得します。true
またはfalse
の文字列が戻されます。
int getPoolSize()
オープンしている物理接続の数を取得します。統計分析用にあくまで目安として使用してください。
int getActiveSize()
オープンしていて、かつ使用中である物理接続の数を取得します。統計分析用にあくまで目安として使用してください。
boolean isPoolCreated()
プールが作成されているかどうかを取得します。実際にプールが作成されるのは、OracleOCIConnection (user, password, url, poolConfig)
をコールしたとき、またはOracleOCIConnection()
をコールした後にsetUser
、setPassword
およびsetURL
を実行したときです。
OracleOCIConnectionPool
クラスは、getConnection
メソッドをコールして、OracleOCIConnection
クラスのインスタンスを作成します。このインスタンスは1つの接続を表します。
OracleOCIConnection
クラスはOracleConnection
クラスを拡張するため、後者のクラスの機能も備えています。ユーザー・セッションが完了したら、OracleOCIConnection
オブジェクトをクローズしてください。クローズしない場合は、このオブジェクトはプール・インスタンスがクローズしたときにクローズされます。
getConnection
をコールするには、次の2つの方法があります。
OracleConnection getConnection()
ユーザー名とパスワードを指定しない場合、接続プールの作成に使用されたデフォルトのユーザー名とパスワードを使用して、接続オブジェクトが作成されます。
OracleConnection getConnection(String user, String password)
このメソッドを使用すると、指定されたユーザー名とパスワードで識別される論理接続を取得します。このユーザー名とパスワードは、プールの作成に使用されたものとは異なります。
次のコードは、オーバーロードされたgetConnection
メソッドのシグネチャを示します。
public synchronized OracleConnection getConnection( ) throws SQLException /* * For getting a connection to the database. * * @param us Connection user-id * @param p Connection password * @return connection object */ public synchronized OracleConnection getConnection(String us, String p) throws SQLException
OracleConnection
の拡張機能として、ユーザーのパスワードを変更するために次のような新しいメソッドがOracleOCIConnection
に追加されています。
void passwordChange (String user, String oldPassword, String newPassword)
次のコードは、サンプル・アプリケーションでのOCI接続プールの使用方法を示しています。
import java.sql.DriverManager; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.util.Properties; import oracle.jdbc.OracleDriver; import oracle.jdbc.pool.OracleOCIConnectionPool; public class conPoolAppl extends Thread { public static final String query = "SELECT object_name FROM all_objects WHERE rownum < 300"; static public void main(String args[]) throws SQLException { int _maxCount = 10; Connection []conn = new Connection[_maxCount]; try { DriverManager.registerDriver(new OracleDriver()); String s = null; //System.getProperty ("JDBC_URL"); //String url = ( s == null ? "jdbc:oracle:oci8:@orcl" : s); String url = "jdbc:oracle:oci8:@orcl.rmmslang.com"; OracleOCIConnectionPool cpool = new OracleOCIConnectionPool("scott", "tiger", url, null); // Print out the default configuration for the OracleOCIConnectionPool System.out.println ("-- The default configuration for the OracleOCIConnectionPool --"); displayPoolConfig(cpool); //Set up the initial pool configuration Properties p1 = new Properties(); p1.put (OracleOCIConnectionPool.CONNPOOL_MIN_LIMIT, Integer.toString(1)); p1.put (OracleOCIConnectionPool.CONNPOOL_MAX_LIMIT, Integer.toString(_maxCount)); p1.put (OracleOCIConnectionPool.CONNPOOL_INCREMENT, Integer.toString(1)); // Enable the initial configuration cpool.setPoolConfig(p1); Thread []t = new Thread[_maxCount]; for (int i = 0; i < _maxCount; ++i) { conn[i] = cpool.getConnection("scott", "tiger"); if ( conn[i] == null ) { System.out.println("Unable to create connection."); return; } t[i] = new conPoolAppl (i, conn[i]); t[i].start (); //displayPoolConfig(cpool); } ((conPoolAppl)t[0]).startAllThreads (); try { Thread.sleep (200); } catch (Exception ea) {} displayPoolConfig(cpool); for (int i = 0; i < _maxCount; ++i) t[i].join (); } catch(Exception ex) { System.out.println("Error: " + ex); ex.printStackTrace (); return; } finally { for (int i = 0; i < _maxCount; ++i) if (conn[i] != null) conn[i].close (); } } //end of main private Connection m_conn; private static boolean m_startThread = false; private int m_threadId; public conPoolAppl (int i, Connection conn) { m_threadId = i; m_conn = conn; } public void startAllThreads () { m_startThread = true; } public void run () { while (!m_startThread) Thread.yield (); try { doQuery (m_conn); } catch (SQLException ea) { System.out.println ("*** Thread id: " + m_threadId); ea.printStackTrace (); } } // end of run private static void doQuery (Connection conn) throws SQLException { PreparedStatement pstmt = null; ResultSet rs = null; try { pstmt = conn.prepareStatement (query); rs = pstmt.executeQuery (); while (rs.next ()) { //System.out.println ("Object name: " +rs.getString (1)); } } catch (Exception ea) { System.out.println ("Error during execution: " +ea); ea.printStackTrace (); } finally { if (rs != null) rs.close (); if (pstmt != null) pstmt.close (); if (conn != null) conn.close (); } } // end of doQuery (Connection) // Display the current status of the OracleOCIConnectionPool private static void displayPoolConfig (OracleOCIConnectionPool cpool) throws SQLException { System.out.println (" Min poolsize Limit: " + cpool.getMinLimit()); System.out.println (" Max poolsize Limit: " + cpool.getMaxLimit()); /* System.out.println (" Connection Increment: " + cpool.getConnectionIncrement()); System.out.println (" NoWait: " + cpool.getNoWait()); System.out.println (" Timeout: " + cpool.getTimeout()); */ System.out.println (" PoolSize: " + cpool.getPoolSize()); System.out.println (" ActiveSize: " + cpool.getActiveSize()); } } // end of class conPoolAppl
文キャッシュは、OracleOCIConnectionPool
でサポートされます。キャッシュを使用すると、カーソルをオープン、解析およびクローズする必要がなくなるため、パフォーマンスが向上します。OracleOCIConnection.prepareStatement
("a_SQL_query
")を処理すると、SQL問合せに一致する文が文キャッシュから検索されます。一致する文が見つかった場合は、別のStatement
オブジェクトを作成するかわりに、同じStatement
オブジェクトを再利用できます。キャッシュ・サイズは動的に増減できます。デフォルトのキャッシュ・サイズは0(ゼロ)です。
注意: OracleOCIConnection クラスから作成したOracleStatement オブジェクトは、OracleConnection から作成したオブジェクトと同じように動作します。 |
Java Naming and Directory Interface(JNDI)機能により、Javaオブジェクトのプロパティが永続化されるため、これらのプロパティを使用して、オブジェクトのクローニングなど、オブジェクトの新しいインスタンスを作成できます。この利点は、古いオブジェクトを解放して、後でまったく同じプロパティを持つ新しいオブジェクトを作成できることです。InitialContext.bind
メソッドは、ファイルまたはデータベースでプロパティを永続化します。一方、InitialContext.lookup
メソッドは永続ストアからプロパティを取得し、これらのプロパティを使用して新しいオブジェクトを作成します。
JNDI機能を使用して、OracleOCIConnectionPool
オブジェクトをバインドしたり、検索したりすることができます。OracleOCIConnectionPool
で新しくインタフェースをコールする必要はありません。