ヘッダーをスキップ
Oracle Database JDBC開発者ガイドおよびリファレンス
11gリリース1(11.1)
E05720-02
  目次
目次
索引
索引

戻る
戻る
次へ
次へ
 

24 OCI接続プーリング

Java Database Connectivity(JDBC)Oracle Call Interface(OCI)ドライバ接続プーリング機能は、JDBCクライアントの一部です。この機能は、OracleOCIConnectionPoolクラスによって提供されます。

JDBCアプリケーションでは、同時に複数のプールを保持できます。複数のプールを保持すると、複数のアプリケーション・サーバーや異なるデータソースの各プールに対応できます。JDBC OCIドライバで提供される接続プーリングでは、アプリケーションで少数の物理接続をすべて使用して、複数の論理接続を保持できます。この論理接続でのコールは、コールの時点で使用可能な物理接続にルーティングされます。

この章では、次の項目について説明します。


注意:

セッションの多重化が必要な場合は、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
    ("SCOTT", "TIGER", "jdbc:oracle:oci:@(description=(address=(host=
    myhost)(protocol=tcp)(port=1521))(connect_data=(INSTANCE_NAME=orcl)))",
    poolConfig);

poolConfigは、接続プールを指定する一連のプロパティです。poolConfigがNULLの場合は、デフォルト値が使用されます。たとえば、次の場合を考えてみましょう。

コンストラクタ・コール以外にも、個々のメソッドを使用してユーザー、パスワードおよび接続文字列を指定して、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クラス属性によって決まります。

これらの属性はすべて動的に構成できます。したがって、アプリケーションではカレント・ロード、つまりオープンしている接続の数と使用中の接続の数を読み取って、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);
...

これらの属性を設定するときは、次の規則に従ってください。


関連項目:

『Oracle Call Interfaceプログラマーズ・ガイド』

OCI接続プール・ステータスのチェック

接続プールのステータスをチェックするには、OracleOCIConnectionPoolクラスの次のメソッドを使用します。

OCI接続プールへの接続

OracleOCIConnectionPoolクラスは、getConnectionメソッドをコールして、OracleOCIConnectionクラスのインスタンスを作成します。このインスタンスは1つの接続を表します。

OracleOCIConnectionクラスはOracleConnectionクラスを拡張するため、後者のクラスの機能も備えています。ユーザー・セッションが完了したら、OracleOCIConnectionオブジェクトをクローズしてください。クローズしない場合は、このオブジェクトはプール・インスタンスがクローズしたときにクローズされます。

getConnectionをコールするには、次の2つの方法があります。

次のコードは、オーバーロードされた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
    {
      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から作成したオブジェクトと同じように動作します。

JNDIおよびOCI接続プール

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

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