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
値のいずれかを使用して、トランザクション分離レベルを変更します。