ヘッダーをスキップ
Oracle® Database JDBC開発者ガイド
12cリリース1 (12.1)
B71308-02
  目次へ移動
目次
索引へ移動
索引

前
 
次
 

22 OCI接続プーリング

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接続プーリングと共有サーバーの主な違いは、共有サーバーを使用する場合、通常はデータベース・インスタンス内のディスパッチャに対してクライアントから接続が行われることです。ディスパッチャは、クライアントからの要求を適切な共有サーバーにリダイレクトします。他方、OCI接続プールからの物理接続は、バックエンド・サーバー・プールにあるOracle専用サーバー・プロセスに対して中間層から直接確立されます。

OCI接続プールが有効なのは、中間層がマルチスレッドである場合のみです。各スレッドは、データベースに対して1つのセッションを保持できます。データベースに対する実際の接続は、OracleOCIConnectionPoolによって保持され、これらの接続は、専用データベース・サーバー・プロセスのプールも含めて、中間層のすべてのスレッドで共有されます。

OCI接続プールの定義

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
    ("HR", "hr", "jdbc:oracle:oci:@(description=(address=(host=
    localhost)(protocol=tcp)(port=5221))(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("HR");
cpool.setPassword("hr");
cpool.setURL("jdbc:oracle:oci:@(description=(address=(host=
    localhost)(protocol=tcp)(port=5221))(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_LIMITCONNPOOL_MAX_LIMITおよびCONNPOOL_INCREMENTパラメータのデフォルト値は、それぞれ11および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_LIMITCONNPOOL_MAX_LIMITおよびCONNPOOL_INCREMENTパラメータは必須です。

  • CONNPOOL_MIN_LIMITの値はゼロより大きくしてください。

  • CONNPOOL_MAX_LIMITは、CONNPOOL_MIN_LIMITCONNPOOL_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()をコールした後にsetUsersetPasswordおよびsetURLを実行したときです。

OCI接続プールへの接続

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接続プーリングのサンプル・コード

次のコードは、サンプル・アプリケーションでの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
    {
      String s = null;   //System.getProperty ("JDBC_URL");
      String url = "jdbc:oracle:oci8:@localhost";
      OracleOCIConnectionPool cpool = new OracleOCIConnectionPool("HR", "hr", 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("HR", "hr");
        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から作成したオブジェクトと同じように動作します。

JNDIおよびOCI接続プール

Java Naming and Directory Interface(JNDI)機能によりJavaオブジェクトのプロパティが存続するため、そのオブジェクトの新しいインスタンスを、それらのプロパティを使用して作成することができます(例: オブジェクトのクローニングなど)。利点は、古いオブジェクトを解放して、正確に同じプロパティを持つ新しいオブジェクトを後で作成できることです。InitialContext.lookupメソッドは永続ストアからプロパティを取得し、そのプロパティを使用して新しいオブジェクトを作成しますが、InitialContext.bindメソッドは、ファイルまたはデータベースにあるプロパティを存続させます。

JNDI機能を使用して、OracleOCIConnectionPoolオブジェクトをバインドしたり、検索したりすることができます。OracleOCIConnectionPoolで新しくインタフェースをコールする必要はありません。