この章では、Oracle Java Database Connectivity(JDBC)拡張要素である文キャッシュの利点と使用方法について説明します。
この章の内容は次のとおりです。
注意: Oracle9iリリース2(9.2)以上では、Oracle9iリリース1(9.0.1)でサポートされていたApplication Program Interface(API)にかわり、Oracle JDBCによって、新しい文キャッシュ・インタフェースと実装が提供されています。以前のAPIは非推奨となりました。 |
文キャッシュにより、繰り返しコールされるループやメソッドなどで何度も使用する実行文がキャッシュされるため、パフォーマンスが向上します。JDBC 3.0以降では、JDBC標準で文キャッシュ・インタフェースが定義されています。
文キャッシュでは、次のことができます。
カーソル作成の繰返しによるオーバーヘッドを回避します。
文の解析と作成の繰返しを回避します。
クライアント内のデータ構造を再利用します。
この項の内容は次のとおりです。
注意: 暗黙的文キャッシュの使用を強くお薦めします。Oracle JDBCドライバは暗黙的文キャッシュが有効になっているという前提で設計されています。このため、文キャッシュを使用しないとパフォーマンスに悪影響を及ぼします。 |
アプリケーションでは、特定の物理接続に関連付けられている文をキャッシュするために文キャッシュを使用します。このキャッシュはOracleConnection
オブジェクトに関連付けられています。OracleConnection
には、文キャッシュを有効にするメソッドが含まれています。文キャッシュを有効にすると、close
メソッドをコールするときに文オブジェクトがキャッシュされます。
物理接続ごとに独自のキャッシュがあるため、複数の物理接続に対して文キャッシュを有効にすると複数のキャッシュが存在することになります。接続キャッシュで文キャッシュを有効にすると、基礎となる物理接続で有効な文キャッシュが論理接続で利用されます。接続キャッシュによって保持されている論理接続で文キャッシュを有効にしようとすると、例外が発生します。
文キャッシュには、暗黙的文キャッシュと明示的文キャッシュの2つのタイプがあります。文キャッシュの各タイプは、互いに関係なく有効または無効にできます。いずれかを有効にするか、いずれも有効にしないか、または両方とも有効にすることができます。両方のタイプの文キャッシュで、接続ごとに1つのキャッシュが共有されます。
暗黙的文キャッシュを有効にすると、JDBCでは、プリコンパイルされたSQL文またはコール可能文の文オブジェクトのclose
メソッドをコールしたときに、その文が自動的にキャッシュされます。プリコンパイルされたSQL文およびコール可能文のキャッシュおよび取出しには、標準の接続オブジェクトおよび文オブジェクト・メソッドを使用します。
暗黙的文キャッシュはSQL文字列をキーとして使用しますが、プレーン文はSQL文字列を使用せずに作成されるため、プレーン文は暗黙的にキャッシュされません。このため、暗黙的文キャッシュは、SQL文字列を使用して作成されるOraclePreparedStatement
およびOracleCallableStatement
オブジェクトにのみ適用されます。OracleStatement
とともに暗黙的文キャッシュを使用することはできません。OraclePreparedStatement
またはOracleCallableStatement
を作成するとき、JDBCドライバはキャッシュを自動的に検索し、一致する文を探します。一致基準は、次のとおりです。
文内のSQL文字列は、キャッシュのSQL文字列と同一である必要があります。
文の種類は、同じにする必要があります。つまり、プリコンパイルされたSQL文またはコール可能文にします。
文によって生成される結果セットのスクロール可能な型は、同じにする必要があります。つまり、forward-onlyまたはscrollableにします。
キャッシュ検索中に一致するものが見つかった場合は、キャッシュされた文が戻されます。一致するものが見つからなかった場合は、新しい文が作成されて戻されます。どちらの場合でも、文は、そのカーソルおよび状態とともに、文オブジェクトのclose
メソッドをコールするとキャッシュされます。
キャッシュされたOraclePreparedStatement
またはOracleCallableStatement
オブジェクトが取り出されると、状態およびデータ情報は自動的に再初期化されて、デフォルト値にリセットされますが、メタデータは保存されます。最大サイズに準拠するため、最低使用頻度(LRU)アルゴリズムを使用してキャッシュから文が削除されます。
注意: JDBCドライバは、メタデータを消去しません。メタデータはパフォーマンスの理由から保存されますが、セマンティクスへの影響はありません。暗黙的キャッシュによる文は、新たに作成された場合と同様に動作します。 |
特定の文を暗黙的なキャッシュの対象から外すことができます。
明示的文キャッシュによって、プリコンパイルされたSQL文およびコール可能文を選択してキャッシュし、取り出すことができます。明示的文キャッシュは、ユーザーが指定する任意のJava String
であるキーに依存します。
注意: プレーン文はキャッシュできません。 |
明示的文キャッシュは文のデータ、状態およびメタデータを保持するため、メタデータのみを保持する暗黙的文キャッシュに対してパフォーマンス上は有利です。ただし、このタイプのキャッシュを使用する場合は慎重である必要があります。明示的文キャッシュは再利用のために3つの種類の情報をすべて保存するため、前回の文の使用から、どのようなデータと状態が保持されているかわからない場合があります。
暗黙的文キャッシュと明示的文キャッシュは次の点が異なります。
文の取出し
暗黙的文キャッシュの場合は、文をキャッシュから取り出すための特別な処理は不要です。かわりに、prepareStatement
またはprepareCall
をコールするたびに、JDBCでは一致する文についてキャッシュが自動的にチェックされ、見つかった場合はその文が戻されます。しかし、明示的文キャッシュの場合は、専用のOracle WithKeyメソッドを使用して、文オブジェクトをキャッシュし、取り出します。
キーの指定
暗黙的文キャッシュでは、プリコンパイルされたSQL文またはコール可能文のSQL文字列がキーとして使用され、ユーザーは特にアクションを実行する必要はありません。これに対し明示的文キャッシュでは、キーとして使用するJava String
を指定する必要があります。
文の戻り
暗黙的文キャッシュの実行中に、JDBCドライバでキャッシュ内に一致する文を見つけられない場合は、新しい文が自動的に作成されます。しかし、明示的文キャッシュの実行中にJDBCドライバでキャッシュ内に一致する文を見つけられない場合は、NULL
値が戻されます。
表20-1で、暗黙的文キャッシュと明示的文キャッシュで使用されるメソッドの違いを比較します。
この項の内容は次のとおりです。
OracleConnection
APIを使用する場合は、暗黙的および明示的な文キャッシュは、互いに関係なく有効または無効にできます。いずれかを有効にするか、いずれも有効にしないか、または両方とも有効にすることができます。
暗黙的文キャッシュの有効化
暗黙的文キャッシュを有効にする方法は2つあります。最初のメソッドは、プールされていない物理接続上で文キャッシュを有効にします。ここでは、setStatementCacheSize
メソッドを使用して、すべての接続に対する文サイズを明示的に指定する必要があります。2番目のメソッドは、プールされている論理接続上で文キャッシュを有効にします。プール内のそれぞれの接続は、MaxStatementsLimit
プロパティを設定することで指定できる最大サイズが同一である、独自の文キャッシュを持っています。
方法1
次の手順を実行します。
接続でOracleDataSource.setImplicitCachingEnabled(true)
メソッドをコールして、OracleDataSource
プロパティimplicitCachingEnabled
をtrue
に設定します。たとえば、次のようになります。
OracleDataSource ods = new OracleDataSource(); ... ods.setImplicitCachingEnabled(true); ...
物理接続でOracleConnection.setStatementCacheSize
メソッドをコールします。引数にはキャッシュ内の文の最大数を指定します。たとえば、次のコードでは、キャッシュ・サイズを10の文に指定します。
((OracleConnection)conn).setStatementCacheSize(10);
方法2
次の手順を実行します。
OracleDataSource
プロパティのimplicitCachingEnabled
およびconnectionCachingEnabled
をtrue
に設定します。たとえば、次のようになります。
OracleDataSource ods = new OracleDataSource(); ... ods.setConnectionCachingEnabled( true ); ods.setImplicitCachingEnabled( true ); ...
接続キャッシュを使用する場合は、接続キャッシュでMaxStatementsLimit
プロパティを正の整数に設定します。たとえば、次のようになります。
Properties cacheProps = new Properties(); ... cacheProps.put( "MaxStatementsLimit", "50" );
暗黙的キャッシュが有効になっているかどうかを判断するには、getImplicitCachingEnabled
をコールします。暗黙的キャッシュが有効な場合はtrue
が、それ以外の場合はfalse
が戻されます。
注意: 文キャッシュを有効にすると、暗黙的文キャッシュと明示的文キャッシュの両方が有効になります。 |
暗黙的文キャッシュの無効化
暗黙的文キャッシュを無効にするには、接続でsetImplicitCachingEnabled(false)
をコールするか、またはImplicitCachingEnabled
プロパティをfalse
に設定します。
明示的文キャッシュの有効化
明示的文キャッシュを有効にするには、最初に文キャッシュ・サイズを設定する必要があります。キャッシュ・サイズを設定するために、物理接続でOracleConnection.setStatementCacheSize
をコールします。引数にはキャッシュ内の文の最大数を指定します。0
(ゼロ)を指定すると、キャッシングは行われません。キャッシュ・サイズのチェックには、次のようにgetStatementCacheSize
メソッドを使用します。
System.out.println("Stmt Cache size is " + ((OracleConnection)conn).getStatementCacheSize());
次のコードでは、キャッシュ・サイズを10の文に指定します。
((OracleConnection)conn).setStatementCacheSize(10);
接続でsetExplicitCachingEnabled(true)
をコールすることにより、明示的文キャッシュを有効にします。
明示的キャッシュが有効になっているかどうかを判断するには、getExplicitCachingEnabled
をコールします。明示的キャッシュが有効な場合はtrue
が、それ以外の場合はfalse
が戻されます。
注意:
|
明示的文キャッシュの無効化
setExplicitCachingEnabled(false)
をコールすることにより、明示的文キャッシュを無効にします。キャッシュを無効化またはクローズすると、そのキャッシュは消去されます。次の例では、明示的文キャッシュを無効にします。
((OracleConnection)conn).setExplicitCachingEnabled(false);
文をクローズし、それが確実にキャッシュに戻されないようにするには次の操作を行います。
J2SE 5.0の場合
その文のキャッシュを無効にします。
stmt.setDisableStatementCaching(true);
文オブジェクトのclose
メソッドをコールします。
stmt.close();
JSE 6.0の場合
stmt.setPoolable(false); stmt.close();
キャッシュされた文の物理的なクローズ
暗黙的文キャッシュを有効にすると、文の物理的なクローズを手動で実行できなくなります。文オブジェクト・キャッシュのclose
メソッドは、文をクローズするのではなく、キャッシュします。文は、次の3つの条件の1つで自動で物理的にクローズされます。
関連付けられている接続がクローズされた場合
キャッシュがそのサイズ制限に達し、LRUアルゴリズムにより、最低使用頻度の文オブジェクトが優先的に取得される場合
文キャッシュが無効にされている文でclose
メソッドをコールした場合
暗黙的文キャッシュを有効にすると、デフォルトではすべてのプリコンパイルされたSQL文およびコール可能文が自動的にキャッシュされます。暗黙的文キャッシュでは、次の手順が実行されます。
暗黙的文キャッシュを有効にします。
標準メソッドの1つを使用して文を割り当てます。
キャッシュの対象としない特定の文に対する暗黙的文キャッシュを無効にします。これは省略可能な手順です。
close
メソッドを使用して文をキャッシュします。
暗黙的にキャッシュされた文を取り出すには、適切な標準のprepareメソッドをコールします。
暗黙的キャッシュのための文の割当て
暗黙的文キャッシュに文を割り当てるには、通常prepareStatement
またはprepareCall
メソッドを使用します。
次のコードでは、pstmt
と呼ばれる新しい文オブジェクトを割り当てます。
PreparedStatement pstmt = conn.prepareStatement ("UPDATE emp SET ename = ? WHERE rowid = ?");
特定の文に対する暗黙的文キャッシュの無効化
ある接続の暗黙的文キャッシュを有効にすると、デフォルトでは、その接続のすべてのコール可能文およびプリコンパイルされたSQL文が自動的にキャッシュされます。特定のコール可能文またはプリコンパイルされたSQL文が暗黙的にキャッシュされないようにするには、文オブジェクトのsetDisableStatementCaching
メソッドを使用します。キャッシュ領域を管理するためには、使用頻度の低い文でsetDisableStatementCaching
メソッドをコールします。
次のコードでは、pstmt
に対する暗黙的文キャッシュを無効にします。
PreparedStatement pstmt = conn.prepareStatement("SELECT 1 from DUAL"); ((OraclePreparedStatement)pstmt).setDisableStmtCaching(true); pstmt.close ();
注意: JSE 6を使用している場合は、標準JDBC 4.0メソッドsetPoolable を使用して文キャッシュを無効にします。
PreparedStatement.setPoolable(false); 次のコマンドを使用して Statement.isPoolable(); |
文の暗黙的なキャッシュ
割り当てられた文をキャッシュするには、文オブジェクトのclose
メソッドをコールします。OraclePreparedStatement
またはOracleCallableStatement
オブジェクトでclose
メソッドをコールすると、この文のキャッシュを無効にしていないかぎり、JDBCドライバではこの文がキャッシュ内に自動的に挿入されます。
次のコードでは、pstmt
文をキャッシュします。
pstmt.close ();
暗黙的にキャッシュされた文の取出し
暗黙的にキャッシュされた文を取り出すには、文の種類に応じて、prepareStatement
またはprepareCall
メソッドをコールします。
次のコードでは、prepareStatement
メソッドを使用して、キャッシュからpstmt
を取り出します。
pstmt = conn.prepareStatement ("UPDATE emp SET ename = ? WHERE rowid = ?");
文を割り当てたり、暗黙的にキャッシュされた文を取り出したりするメソッドについて、表20-2で説明します。
表20-2 文の割当ておよび暗黙的文キャッシュで使用されるメソッド
メソッド | 暗黙的文キャッシュの機能 |
---|---|
目的のキャッシュされた |
|
目的のキャッシュされた |
例20-1は、暗黙的文キャッシュを有効にする方法を示すサンプル・コードです。
例20-1 暗黙的文キャッシュの使用
import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.util.Properties; import javax.sql.DataSource; import oracle.jdbc.OracleConnection; import oracle.jdbc.pool.OracleDataSource; public class TestJdbc { /** * Get a Connection, prepare a statement, execute a query, fetch the results, close the connection. * @param ods the DataSource used to get the connection. */ private static void doSQL( DataSource ods ) throws SQLException { final String SQL = "select username from all_users"; OracleConnection conn = null; PreparedStatement ps = null; ResultSet rs = null; try { conn = (OracleConnection) ods.getConnection(); System.out.println( "Connection:" + conn ); System.out.println( "Connection getImplicitCachingEnabled:" + conn.getImplicitCachingEnabled() ); System.out.println( "Connection getStatementCacheSize:" + conn.getStatementCacheSize() ); ps = conn.prepareStatement( SQL ); System.out.println( "PreparedStatement:" + ps ); rs = ps.executeQuery(); while ( rs.next() ) { String owner = rs.getString( 1 ); System.out.println( owner ); } } finally { if ( rs != null ) { rs.close(); } if ( ps != null ) { ps.close(); conn.close(); } } } public static void main( String[] args ) { try { OracleDataSource ods = new OracleDataSource(); ods.setDriverType( "thin" ); ods.setServerName( "localhost" ); ods.setPortNumber( 1521 ); ods.setServiceName( "orcl" ); ods.setUser( "scott" ); ods.setPassword( "tiger" ); ods.setConnectionCachingEnabled( true ); ods.setImplicitCachingEnabled( true ); Properties cacheProps = new Properties(); cacheProps.put( "InitialLimit", "1" ); cacheProps.put( "MinLimit", "1" ); cacheProps.put( "MaxLimit", "5" ); cacheProps.put( "MaxStatementsLimit", "50" ); ods.setConnectionCacheProperties( cacheProps ); System.out.println( "DataSource getImplicitCachingEnabled: " + ods.getImplicitCachingEnabled() ); for ( int i = 0; i < 5; i++ ) { doSQL( ods ); } } catch ( Exception ex ) { ex.printStackTrace(); } } }
明示的文キャッシュを有効にすると、プリコンパイルされたSQL文またはコール可能文を明示的にキャッシュできます。明示的文キャッシュでは、次の処理が行われます。
明示的文キャッシュを有効にします。
標準メソッドの1つを使用して文を割り当てます。
明示的にキャッシュされた文を取り出すには、適切なWithKeyメソッドをコールして、適切なキーを指定します。
オープンしている、明示的にキャッシュされた文を再キャッシュするには、closeWithKey
メソッドを使用して文を再度クローズします。キャッシュされた文をクローズするたびに、そのキーを使用して文を再キャッシュします。
明示的なキャッシュのための文の割当て
明示的文キャッシュに文を割り当てるには、通常createStatement
、prepareStatement
またはprepareCall
メソッドを使用します。
次のコードでは、pstmt
と呼ばれる新しい文オブジェクトを割り当てます。
PreparedStatement pstmt = conn.prepareStatement ("UPDATE emp SET ename = ? WHERE rowid = ?");
文の明示的なキャッシュ
割り当てられた文を明示的にキャッシュするには、文オブジェクトのcloseWithKey
メソッドをコールして、キーを指定します。キーは、ユーザーが指定する任意のJava String
です。closeWithKey
メソッドは、文をそのままキャッシュします。つまり、データ、状態およびメタデータは消去されずに保持されます。
次のコードでは、"mykey"
キーを使用してpstmt
文をキャッシュします。
((OraclePreparedStatement)pstmt).closeWithKey ("mykey");
明示的にキャッシュされた文の取出し
明示的にキャッシュされた文を再度コールするには、文の種類によって、getStatementWithKey
またはgetCallWithKey
メソッドをコールします。
指定したキーを使用して文を取り出す場合は、指定したキーに基づいて、JDBCドライバがキャッシュ内でその文を検索します。一致する文が見つかった場合、一致する文は、状態、データおよびメタデータとともに戻されます。情報は、文が最後にクローズしたときの状態で戻されます。一致する文が見つからない場合は、JDBCドライバでnull
が戻されます。
次のコードでは、getStatementWithKey
メソッドで"mykey"
キーを使用して、キャッシュからpstmt
を再度コールします。pstmt
文オブジェクトは"mykey"
キーでキャッシュされていました。
pstmt = ((OracleConnection)conn).getStatementWithKey ("mykey");
pstmt
文オブジェクトでcreationState
メソッドをコールすると、メソッドはEXPLICIT
を戻します。
重要: 明示的にキャッシュされた文を取り出す場合は、キーを指定するときに文の種類に適したメソッドを使用してください。たとえば、prepareStatement メソッドを使用して文を割り当てた場合は、getStatementWithKey メソッドを使用してキャッシュから文を取り出します。JDBCドライバは、戻す文の型を検証しません。 |
明示的にキャッシュされた文を取り出す場合に使用するメソッドについて、表20-3で説明します。
JDBC 3.0の仕様で導入された文プーリングでは、アプリケーションは、Connection
オブジェクトの使用と同様にしてPreparedStatement
オブジェクトを再利用することができます。PreparedStatement
オブジェクトは、複数の論理接続が透過的に再利用できます。
この項の内容は次のとおりです。
注意: Oracle JDBCドライバでは、文のプーリングをサポートするために、暗黙的文キャッシュを使用します。 |
Statement
インタフェースからisPoolable
メソッドをコールすることによって、データソースが文プーリングをサポートするかどうかを認識できます。戻り値がtrue
の場合、アプリケーションはPreparedStatement
オブジェクトがプールされていることを認識しています。アプリケーションはまた、Statement
インタフェースからsetPoolable
メソッドをコールすることによって、文がプールされるようにするかどうかを指定することができます。
プールされた文の再利用は、アプリケーションに対して完全に透過的である必要があります。つまり、PreparedStatement
オブジェクトが文プーリングに関与するかどうかにかかわらず、アプリケーション・コードが同じままであることが必要です。アプリケーションがPreparedStatement
オブジェクトをクローズした場合、再利用する際はConnection.prepareStatement
メソッドをコールする必要があります。
注意: アプリケーションは、文がどのようにプールされるかを、直接的に制御しません。文のプールはPooledConnection オブジェクトに関連付けられます。このオブジェクトの動作は、それを作成したConnectionPoolDataSource オブジェクトのプロパティによって決定されます。 |
アプリケーションがプールされた文をクローズする方法は、プールされていない文をクローズする方法と完全に同じです。プールされた文であってもプールされていない文であっても、一度クローズされると、その文をアプリケーションが使用することはできず、再利用しようとすると例外がスローされる原因になります。認識できる唯一の相違点は、プールされる物理文をアプリケーションが直接クローズすることができないということです。その操作はプール・マネージャが行います。メソッドPooledConnection.closeAll
は、指定の物理接続上でオープンしている文をすべてクローズします。これにより、それらの文に関連付けられているリソースが解放されます。
次のメソッドは、プールされた文をクローズすることができます。
このjava.sql.Statement
インタフェース・メソッドはアプリケーションによってコールされます。文がプールされる場合、アプリケーションが使用する論理文はクローズされますが、プールされた物理文はクローズされません。
このjava.sql.Connection
インタフェース・メソッドはアプリケーションによってコールされます。このメソッドは、文を使用する接続がプールされるかどうかに応じて、異なる動作をします。
プールされていない接続
このメソッドは、物理接続が作成したすべての接続とすべての文をクローズします。こうする必要があるのは、外部的に管理されているリソースをいつ解放できるかは、ガーベジ収集メカニズムで検出できないためです。
プールされた接続
このメソッドは論理接続とそれが戻した論理文をクローズしますが、その基礎となるPooledConnection
オブジェクトや、関連付けられているプールされた文はオープンされた状態に残します。
PooledConnection.closeAll
このメソッドは、PooledConnection
オブジェクトによってプールされる物理文をすべてクローズするために接続プール・マネージャによってコールされます。
アプリケーションでは、データベースに問合せを繰返し送信することがあります。繰返しの問合せのレスポンス時間を改善するには、問合せの結果、問合せフラグメントおよびPL/SQLファンクションをメモリーにキャッシュできます。結果キャッシュには、すべてのセッションにわたって共有される問合せの結果が格納されます。これらの問合せを繰返し実行すると、結果がキャッシュ・メモリーから直接取り出されます。
結果が問合せ結果キャッシュに格納されることを示すには、問合せまたは問合せフラグメントに結果キャッシュのヒントで注釈を付ける必要があります。
問合せ結果セットは、次の方法でキャッシュできます。
注意:
|
サーバー側結果セット・キャッシュは、Oracle Database 11gリリース1(11.1)から、JDBC ThinおよびJDBC Oracle Call Interface(OCI)の両方のドライバに対してサポートされるようになりました。サーバー側結果キャッシュは、現在の問合せ、問合せフラグメントおよびPL/SQLファンクションの結果をメモリーにキャッシュし、その問合せ、問合せフラグメントまたはPL/SQLファンクションをその後実行する際に、キャッシュした結果を使用するためのものです。キャッシュした結果はSGAの結果キャッシュ・メモリー部分に存在します。結果キャッシュを作成したときに使用されたデータベース・オブジェクトが正常に変更されると、キャッシュされた結果は自動的に無効になります。サーバー側キャッシュには、次の2つのタイプがあります。
SQL問合せ結果キャッシュ
PL/SQLファンクション結果キャッシュ
関連項目:
|
Oracle Database 11gリリース1(11.1)から、JDBC OCIドライバーに対してクライアント結果キャッシュがサポートされるようになりました。クライアント結果キャッシュは、問合せ結果セットをキャッシュすることで、次回以降の問合せ実行がサーバーから行をフェッチせずキャッシュされた結果にアクセスすることを可能にし、アプリケーションのパフォーマンスを改善します。これにより、キャッシュされた結果を取り出すためにサーバーに何度もラウンドトリップを行うことがなくなり、サーバーのCPUの使用量が減少します。クライアント結果キャッシュでは、キャッシュされた結果セットに影響を与える可能性のあるすべてのセッション状態やデータベース変更と一致するように、結果セットを透過的に維持します。これにより、回数の多いクライアントのSQL問合せ実行や行のフェッチでの応答時間が大幅に改善されます。消費されるCPU時間が減少するため、サーバーでのスケーラビリティは向上します。