C JDBCコーディングのヒント
この付録では、Java Database Connectivity (JDBC)アプリケーションの最適化の方法について説明します。次の内容について説明します。
C.1 JDBCとマルチスレッド
Oracle JDBCドライバは、Javaマルチスレッドを使用するアプリケーションを完全にサポートし、それに対応するように最適化されています。接続キャッシュによって提供されるアクセスなど、接続に対する制御されたシリアル・アクセスが必要であり、そのようなアクセス方法をお薦めします。ただし、複数スレッド間でのデータベース接続の共有はお薦めしません。複数のスレッドが1つの接続に同時にアクセスできないようにしてください。複数のスレッドで接続を共有する必要がある場合は、規則的な使用開始/使用終了の方法を使用してください。
マルチスレッド・アプリケーションでの作業時には、次の点に注意してください。
- 
                        Connectionオブジェクトをローカル変数として使用します。
- 
                        メソッドを終了する前に finallyブロックで接続をクローズします。次に例を示します。Connection conn = null; try { ... } finally { if(conn != null) conn.close(); }
- 
                        スレッド間で Connectionオブジェクトを共有しないでください。
- 
                        同期は内部でドライバによって行われるので、JDBCオブジェクトを同期しないでください。 
- 
                        別のスレッドから時間がかかる問合せを取り消すのではなく、 Statement.setQueryTimeoutメソッドを使用して問合せを実行する時間を設定します。
- 
                        SELECT、UPDATEまたはDELETEなどのSQL操作のためにStatement.cancelメソッドを使用します。
- 
                        COMMIT、ROLLBACKなどのSQL操作のためにConnection.cancelメソッドを使用します。
- 
                        Thread.interruptメソッドを使用しないでください。
C.2 JDBCプログラムのパフォーマンスの最適化
C.2.1 自動コミット・モードの無効化
自動コミット・モードは、SQL操作を実行するたびに自動的にCOMMIT操作を発行するかどうかを、データベースに対して指示します。自動コミット・モードにすると、異なるバインド変数で同じ文を繰り返すような場合などに、時間と処理能力の面で大きな負荷がかかる場合があります。
                        
デフォルトでは、新規の接続オブジェクトは自動コミット・モードが有効になります。ただし、接続オブジェクトjava.sql.Conectionまたはoracle.jdbc.OracleConnectionのどちらかのsetAutoCommitメソッドで自動コミット・モードを無効にできます。
                        
自動コミット・モードでは、文が完了した時点または次の実行が発生した時点のうち、どちらか早い方でCOMMIT操作が発生します。ResultSetオブジェクトを戻す文の場合は、結果セットの最後の行が取り出されたとき、または結果セットがクローズしたときに文が完了します。より複雑なケースでは、1つの文で出力パラメータ値や複数の結果が返されることがあります。この場合、すべての結果および出力パラメータ値が取り出された時点でCOMMITが発生します。 
                        
setAutoCommit(false)をコールして自動コミット・モードを無効にした場合、接続オブジェクトのcommitまたはrollbackメソッドを使用して、操作のグループを手動でコミットまたはロールバックする必要があります。
                        
例
次に、ドライバをロードしてデータベースに接続する例を示します。新しい接続はデフォルトで自動コミット・モードが有効になるので、この例では自動コミットを無効にする方法を示します。この例では、connはConnectionオブジェクトを、stmtはStatementオブジェクトを表します。 
                        
// Connect to the database 
// You can put a database host name after the @ sign in the connection URL.
   OracleDataSource ods = new OracleDataSource();
   ods.setURL("jdbc:oracle:oci:@");
   ods.setUser("HR");
   ods.setPassword("hr");
   Connection conn = ods.getConnection();
    
// It's faster when auto commit is off 
conn.setAutoCommit (false);
// Create a Statement 
Statement stmt = conn.createStatement (); 
...
C.2.2 標準フェッチ・サイズとOracle行プリフェッチ
Oracle JDBC接続オブジェクトや文オブジェクトでは、データベースにアクセスするたびにクライアントにプリフェッチする行数を指定できますが、結果セットは問合せ時に設定されます。接続オブジェクトに値を設定して、その接続で作成される各々の文に適用することも、任意の個別の文オブジェクト内でその値をオーバーライドすることもできます。接続オブジェクトのデフォルト値は、10です。クライアントにデータをプリフェッチすると、サーバーへのラウンドトリップの回数を減らすことができます。
JDBC 2.0では、同様かつさらに柔軟に、文オブジェクトにも(後続の問合せに影響)、結果セット・オブジェクトにも(行の再フェッチに影響)、1回のラウンドトリップでフェッチする行の数を指定できます。デフォルトでは、その結果セットを作成した文オブジェクトの値が、結果セットで使用されます。JDBC 2.0フェッチ・サイズを設定しないと、Oracle接続行プリフェッチ値がデフォルトとして使用されます。
関連トピック
C.2.3 セッション・データ・ユニット・サイズの設定について
セッション・データ・ユニット(SDU)は、Oracle Netがネットワーク間でデータを転送する前にデータを格納するバッファです。Oracle Netがバッファ内のデータを送信するのは、リクエストが完了したときか、バッファがいっぱいのときです。
SDUを構成すると、特に次の利点があります。
- 
                              ネットワーク間でのSQL問合せおよび結果の転送に要する時間の削減 
- 
                              大量のデータの転送 
ノート:
SDUサイズの設定を大きくすると、クライアント・プロセスおよびサーバー・プロセスのフットプリントは増加します。
ここでは、以下の項目について説明します。
C.2.3.1 データベース・サーバーのSDUサイズの設定について
データベース・サーバーのSDUサイズを設定するには、sqlnet.oraファイルでDEFAULT_SDU_SIZEパラメータを構成します。
                           
C.2.3.2 JDBC OCIクライアントのSDUサイズの設定について
JDBC OCIクライアントでは、Oracle Netレイヤーが使用されます。そのため、sqlnet.oraファイルでDEFAULT_SDU_SIZEパラメータを構成すると、JDBC OCIクライアントのSDUサイズを設定できます。
                           
C.2.4 JDBCバッチ更新機能
Oracle JDBCドライバでは、プリペアド文のINSERT、DELETEおよびUPDATEの各操作をクライアントに蓄積し、サーバーに一括送信できます。この機能により、サーバーへのラウンドトリップの回数が低下します。
                        
ノート:
バッチ・サイズを100以下の範囲に保つことをお薦めします。バッチが大きくなると、パフォーマンスはほとんど、またはまったく向上せず、実際には、大きなバッチを処理するために必要なクライアント・リソースのために、パフォーマンスが低下する可能性があります。
C.2.5 文キャッシュ
文キャッシュにより、繰り返しコールされるループやメソッドなどで何度も使用する実行文がキャッシュされるため、パフォーマンスが向上します。アプリケーションでは、特定の物理接続に関連付けられている文をキャッシュするために文キャッシュを使用します。文キャッシュを有効にすると、closeメソッドをコールするときに文オブジェクトがキャッシュされます。物理接続ごとに独自のキャッシュがあるため、複数の物理接続に対して文キャッシュを有効にすると複数のキャッシュが存在することになります。
                        
ノート:
Oracle JDBCドライバは、Oracle文キャッシュで使用するために最適化されています。Oracle文キャッシュ(暗黙的または明示的)を使用することを強くお薦めします。
接続キャッシュで文キャッシュを有効にすると、基礎となる物理接続で有効な文キャッシュが論理接続で利用されます。接続キャッシュによって保持されている論理接続で文キャッシュを有効にしようとすると、例外が発生します。
関連トピック
C.2.6 組込みSQL型とJava型間のマッピング
SQL組込み型とはNUMBER、CHARなど、システム定義の名前を持つ型のことで、ユーザー定義の名前を持つ、Oracleオブジェクト、varrayおよびネストされた表型とは異なります。組込みSQL型のデータにアクセスするJDBCプログラムでは、プログラム・コンテキストによりSQLデータの変換先Java型が決定されるため、型変換はすべて一意です。
                        
表C-1 SQLデータ型とSQLデータ型を表すJavaクラスのマッピング
| SQLデータ型 | ORACLEマッピング - SQLデータ型を表すJavaクラス | 
|---|---|
|   | 
 | 
|   | 
 | 
|   | 
 | 
|   | 
 | 
|   | 
 | 
|   | 
 | 
|   | 
 | 
|   | 
 | 
|   | 
 | 
|   | 
 | 
|   | 
 | 
|   | 
 | 
|   | 
 | 
|   | 
 | 
| ネストした表 | 
 | 
| varray | 
 | 
| SQLオブジェクト値 | 型マップにオブジェクト値のエントリがない場合: 
 型マップにオブジェクト値のエントリがある場合: 
 | 
| SQLオブジェクト型へのREF | 通常、 | 
脚注1
Oracle Database 12cリリース1 (12.1)以降、oracle.sql.CLOBクラスは非推奨となり、oracle.jdbc.OracleClobインタフェースに置き換えられています。
                        
脚注2
Oracle Database 12cリリース1 (12.1)以降、oracle.sql.BLOBクラスは非推奨となり、oracle.jdbc.OracleBlobインタフェースに置き換えられています。
                        
脚注3
Oracle Database 12cリリース1 (12.1)以降、oracle.sql.ARRAYクラスは非推奨となり、oracle.jdbc.OracleArrayインタフェースに置き換えられています。
                        
脚注4
Oracle Database 12cリリース1 (12.1)以降、oracle.sql.STRUCTクラスは非推奨となり、oracle.jdbc.OracleStructインタフェースに置き換えられています。
                        
脚注5
Oracle Database 12cリリース1 (12.1)以降、oracle.sql.REFクラスは非推奨となり、oracle.jdbc.OracleRefインタフェースに置き換えられています。
                        
数値データにアクセスする最も効率的な方法は、int、float、longおよびdoubleなどのプリミティブJava型としてアクセスする方法です。ただし、これらの型の範囲は、SQL NUMBERデータ型の値の範囲と正確には一致しません。このため、一部の情報が失われる可能性があります。値の範囲全体で絶対的な精度が必要である場合は、BigDecimal型を使用します。
                        
文字データはすべて、JavaのUCS2文字セットに変換されます。文字データにアクセスする最も効率的な方法は、java.lang.Stringとしてアクセスする方法です。最も問題となるのは、データベース文字セットの2つ以上の文字が1つのUCS2キャラクタにマップされる場合に、情報が失われる可能性があることです。Oracle Database 11g以降、文字セットのすべての文字がUCS2文字セットの文字にマップされます。ただし、一部の文字はサロゲート・ペアにマップされます。
                        
C.3 JDBCのトランザクション分離レベルとアクセス・モード
読取り専用接続は、Oracle JDBCドライバではサポートされていますが、Oracleサーバーではサポートされていません。
トランザクションの場合、Oracleサーバーでサポートしているトランザクション分離レベルはTRANSACTION_READ_COMMITTEDおよびTRANSACTION_SERIALIZABLEのみです。デフォルトはTRANSACTION_READ_COMMITTEDです。レベルの取出しおよび設定を行うには、oracle.jdbc.OracleConnectionクラスの次のメソッドを使用します。 
                     
- 
                           getTransactionIsolation: 現在のトランザクション分離レベルの接続を取得します。
- 
                           setTransactionIsolation:TRANSACTION_READ_COMMITTED値またはTRANSACTION_SERIALIZABLE値のいずれかを使用して、トランザクション分離レベルを変更します。