JDBC の最適化

このセクションでは、データベースへのアクセス時のコーディング作業を効率化する方法について説明します。

データベースコネクションプールの使用

コネクションプールを使用すると、データベース接続はリクエストごとに作成され廃棄されるのではなく、いったん借用されて、再利用可能なオブジェクトのプールに戻されます。JRun には、独自のコネクションプールメカニズムが組み込まれており、デフォルトで、データソースを JMC に追加するたびに有効になります。

JRun のデータソースを使用していない場合は、独自にカスタマイズしたコネクションプールのメカニズムを実装する必要があります。

JMC 内では影響を受けないオプションの設定を使用して、JRun のデータソースを操作できます。これらのすべての設定はオプションです。次の表で、これらの設定について説明します。
パラメータ
説明
デフォルト
native-results
キャッシュ、スクロールおよび更新が可能な JRun ResultSet 実装を使用するには true に
設定します。
その下にある JDBC ドライバによって返される ResultSet を使用するには false に設定します。
true
initial-connections
プールのインスタンス化時に JRun が作成
する接続の数を設定します。
1
pool-statements
呼び出しのたびに PreparedStatements を再作成せずにプールしておくには、true に設定します。
true
minimum-size
JRun がプール内で保持するオブジェクトの
最小数を設定します。
0
maximum-size
JRun がプール内で保持するオブジェクトの
最大数を設定します。
2147483647
maximum-soft
プールの最大サイズに到達したが、リクエストがまだオブジェクト上で待機している場合に、コネクションプールで新しい緊急のオブジェクトが作成されるようにするには、true に設定します。それによってプールのサイズは一時的に大きくなりますが、スキマーがアクティブになると、プールは自動的に許容可能なサイズに縮小します。
オブジェクトが使用可能になるまでリクエストを待機させるには、false に設定します。
スキマーの詳細については、skimmer-frequency の設定を参照してください。
true
connection-timeout
JRun が接続を廃棄するまでの休止状態を維持する時間 (秒) を設定します。
1200
user-timeout
接続が自動的にプールに戻されるまでにユーザーが接続を維持する時間 (秒) を設定します。
20
skimmer-frequency
プールスキマーがリープサイクルの間で待機
する時間 (秒) を設定します。スキマーは各リープサイクルですべての接続 (チェックインした接続とチェックアウトした接続の両方) を評価して、それらの接続がタイムアウトに
なった場合に自動的にプールに戻すか、
あるいは廃棄するかを決めます。
420
shrink-by
1 つのリープサイクルでプールから削除できるオブジェクトの最大数を設定します。
JRun は、スキマーによってプールが縮小されるたびにこの値を確認します。そのため、JRun のコネクションプールメカニズムによってピーク時にプールが急激に縮小されるのを防ぎます。
5
debugging
冗長なロギング情報を有効にするには、
true に設定します。
false
cache-enabled
クエリ/ResultSet のキャッシュを有効にするには、true に設定します。
false
cache-size
キャッシュできるクエリ/ResultSet のペアの最大数を設定します。
5
cache-refresh-interval
キャッシュがデータベースからその ResultSet をリロードする間隔 (秒) を設定します。
30
remove-on-exceptions
SQLException がある場合にプールから接続を削除するには、true に設定します。
false

コネクションプールの設定を変更するには、jrun-resources.xml ファイル内の適切なデータソースのプロパティを編集します。たとえば、次の設定により、デフォルトの skimmer-frequency 値の 420 をオーバーライドし、100 に置き換えます。

<datasource>
...
 <skimmer-frequency>100</skimmer-frequency>
...
</datasource>

PreparedStatement の使用

データベースにクエリを実行すると、JRun はクエリをコンパイルし、データベース接続を介してデータベースに送信します。頻繁に使用するクエリには PreparedStatement を使用できます。PreparedStatement はプリコンパイルされ、サーバに保管されています。PreparedStatement には ? を使用して変数を任意の数だけ指定できます。これらの変数は実行時にクエリに挿入されます。

次のコード例は、3 つの変数を使用して PreparedStatement を作成する方法を示しています。

String sqlstmt = "INSERT INTO SESSIONS VALUES(?,?,?)";
try {
 InitialContext ctx = new InitialContext();
 DataSource ds = (DataSource) ctx.lookup(dsName);
 conn = ds.getConnection();
 ps = conn.prepareStatement(sqlstmt);
 ps.setString(1,sid);
 ps.setLong(2,time);
 ps.setInt(3,1);
 rs = ps.executeQuery();
} catch (SQLException sqle) {
...
}
...

PreparedStatement オブジェクトの使用方法の詳細については、Java 2 API のドキュメントを参照してください。

Connection、Statement、および ResultSet オブジェクトを閉じる

Connection、Statement、および ResultSet オブジェクトを使用したら、これらのオブジェクトを閉じて、要求されたリソースを解放し、使用されていない接続をプールに戻す必要があります。次の例のように finally ブロックを追加します。

...
} finally {
 try {
  ps.close();
  rs.close();
 } catch (Exception e) {
  e.printStackTrace();
 }
}

フェッチおよび行数の制限

ResultSet および Statement オブジェクトには、次のようなデータベースオペレーションの微調整に役立つ多数のメソッドが用意されています。

setFetchSize および setMaxRows メソッドは、開発者の間でもよく混同されます。これらのメソッドは ResultSet または Statement オブジェクト上で呼び出すことができます。これらのメソッドの違いを理解するには、まずデータベースがクエリの結果を返すときの動作を理解する必要があります。次のセクションでは、データベースにクエリを実行する方法、および setFetchSize メソッドと setMaxRows メソッドの違いについて説明します。

データベースクエリの概要

データベースに対してクエリを実行すると、データベースはクエリを処理し、結果データをそのキャッシュに保管します。ResultSet オブジェクトは、データベースのキャッシュ内にフェッチサイズと同数のレコードへのリファレンスを保持します。つまり、ResultSet オブジェクトはデータベースへのオープン接続にすぎず、返された行のデータは含んでいません。

JRun サーバとデータベース間の接続を確立する JDBC ドライバが、データベースキャッシュから行の一部を取得し、それを処理するクライアントサイド (JRun サーバがデータベースのクライアントに相当) に返します。ドライバは、getFetchSize と同数の行を取得します。

クライアントがドライバによって提供された行の処理を終了したら、JDBC ドライバは次の getFetchSize 行をあらかじめフェッチし、同様の処理を続けます。

setMaxRows の使用

データベースがクエリから返す行の数を制限するには、次の例のように setMaxRows を使用します。

Statement stmt = conn.createStatement();
stmt.setMaxRows(10);
ResultSet rs = stmt.executeQuery("SELECT * from SESSIONS");

データベースが返す行の数を制限するには、SQL ステートメントで LIMIT コマンドを使用することもできます。次の例は、100 行に制限された ResultSet を示しています。

rs = ps.executeQuery("SELECT * FROM tablename LIMIT 100");

setFetchSize の使用

JDBC ドライバがデータベースキャッシュから取得して JRun に返す行の数を設定するには、setFetchSize を使用します。データに多くの処理を行う必要がある場合は、小さい値に設定します。

メモ:  setFetchSize メソッドは、データをフェッチする方法についてのデータベースへのヒントにすぎません。すべてのデータベースドライバでこのメソッドをサポートしているとはかぎりません。

適切な setFetchSize を決めるには、フロントエンドでのユーザー操作と、ユーザーがクエリの結果を操作する方法について検討します。たとえば、ユーザーがユーザーインターフェイスで一回に 10 行を操作できる場合は、フェッチサイズを 10 に設定します。

setFetchDirection の使用

setFetchDirection の処理時に最後の行を最初に返すには、setFetchDirection メソッドを使用します。それによって、大量のデータを操作する際は特に、処理速度が速くなります。

たとえば、日付別に保管されているトランザクションの ResultSet がある場合に、直前のトランザクションを最初のフェッチで取得できます。

メモ:  setFetchDirection メソッドは、データをフェッチする方法についてのデータベースへのヒントにすぎません。すべてのデータベースドライバでこのメソッドをサポートしているとはかぎりません。

次のコードは、フェッチ方向を反転させる例を示しています。

ResultSet rs = null;
Connection conn = null;
String sql = "SELECT * FROM employee";
Statement stmt = 
conn.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE, 
ResultSet.CONCUR_READ_ONLY);
rs.setFetchDirection(ResultSet.FETCH_REVERSE);
rs = stmt.executeQuery(sql);

JDBC ドライバのテスト

すべての JDBC ドライバが一様に動作するとはかぎりません。さまざまな負荷をかけてさまざまなデータベースで各種ドライバの動作をテストして、Web アプリケーションに最適な組み合わせを調べます。

JDBC と ODBC bridge は、絶対に必要な場合にのみ使用してください。

JDBC ドライバの詳細については、Sun の Web サイト
http://industry.java.sun.com/products/jdbc/drivers をご覧ください。

スタティックデータのキャッシュ

データベースにアクセスする最も速い方法は、データベース自体にまったくアクセスしないことです。可能な場合は、データベースへの呼び出しによってスタティックデータをダイナミックに取得するのではなく、キャッシュするようにしてください。サーブレットおよび JSP の init メソッドおよび jspInit メソッド内で、初期化時にデータベースへのアクセスを 1 つのクエリに制限します。さらに、結果をキャッシュし、残りのリクエストがそのキャッシュに入ったデータにアクセスできるようにします。詳細については、次のセクションを参照してください。

「init メソッドでのスタティックデータのキャッシュ」

「jspInit でのスタティックデータのキャッシュ」