Oracle Java Database Connectivity(JDBC)ドライバは、様々なバージョンのJDBC標準機能をサポートしています。Oracle Database 12cリリース1 (12.1)では、Oracle JDBCドライバが強化され、JDBC 4.1標準がサポートされました。これらの機能は、oracle.jdbcパッケージとoracle.sqlパッケージによって提供されます。これらのパッケージでは、Java Development Kit(JDK)リリース6と7がサポートされています。この章では、Oracle JDBCドライバでのJDBC標準のサポートについて説明します。この章には次の項目があります。
JDK 1.2以降のバージョンはJDBC 2.0機能をサポートしています。考慮すべき点が3つあります。
オブジェクト、配列およびラージ・オブジェクト(LOB)などのデータ型のサポート。これはjava.sqlパッケージを介して処理されます。
結果セットの拡張およびバッチ更新などの標準機能のサポート。これは、JDK 1.2.x以降でConnection、ResultSetおよびPreparedStatementなどの標準オブジェクトを介して処理されます。
JDBC 2.0 Optional Packageの機能など、Standard Extension Application Program Interface(API)とも呼ばれる拡張機能に対するサポート。たとえばデータソース、接続プーリングおよび分散トランザクションなどがあげられます。
この項の内容は次のとおりです。
|
注意: 5.0より前のJDKのバージョンは、もうサポートされていません。oracle.jdbc2パッケージは削除されました。 |
Oracle JDBCは、標準java.sqlパッケージ内のインタフェースの実装による標準JDBC 2.0機能を含む、JDK 6およびJDK 7を完全にサポートしています。これらのインタフェースは、oracle.sqlパッケージとoracle.jdbcパッケージ内のクラスによって、適宜実装されます。
ojdbc6.jarのJDBCクラスを使用するJDK 6.0環境では、スクロール可能結果セット、更新可能結果セット、バッチ更新などのJDBC 2.0機能は、標準のJDBC 2.0インタフェースによって指定されたメソッドを介してサポートされます。
データソース、接続プーリングおよび分散トランザクションなどのJDBC 2.0 Optional Packageの各機能は、JDK 1.2.x以上の環境でサポートされます。
標準javax.sqlパッケージとそのインタフェースを実装するクラスは、Oracle Databaseでパッケージ化されたJavaアーカイブ(JAR)ファイルに格納されています。
以前はOracle拡張機能として提供されていた次のパフォーマンス拡張機能は、JDBC2.0で使用できます。
|
注意: Oracle Database 12cリリース1 (12.1)以降、Oracleバッチ更新は非推奨です。Oracleバッチ更新のかわりに標準のJDBCバッチを使用することをお薦めします。 |
バッチ更新
フェッチ・サイズまたは行プリフェッチ
どちらの場合でも、標準モデルまたはOracleモデルを使用するオプションがあります。可能なかぎりJDBC標準モデルの使用をお薦めします。ただし、これらの機能のために、1つのアプリケーション内で標準モデルとOracleモデルを同時に使用しないでください。
標準のJDBC 3.0の機能は、JDK 1.4以降のバージョンでサポートされています。表3-1では、Oracle Database 12cリリース1 (12.1)でサポートしているJDBC 3.0機能と、各機能に関する詳細の参照先を示しています。
表3-1 JDBC 3.0機能の主な領域
| 機能 | コメントと参照 |
|---|---|
|
トランザクション・セーブポイント |
詳細は、「トランザクション・セーブポイント」を参照してください。 |
|
文キャッシュ |
接続プーリングによってコンパイルされたSQL文を再使用します。第20章「文キャッシュと結果セット・キャッシュ」を参照してください。 |
|
ローカル・トランザクションとグローバル・トランザクションの切替え |
「ローカル・トランザクションとグローバル・トランザクションの切替え」を参照してください。 |
|
LOBの変更 |
「JDBC 3.0のLOBインタフェース・メソッド」を参照してください。 |
|
名前付きSQLパラメータ |
「インタフェースoracle.jdbc.OracleCallableStatement」および「インタフェースoracle.jdbc.OraclePreparedStatement」を参照してください。 |
|
RowSet |
第18章「JDBC RowSet」を参照してください。 |
|
自動生成キーの取出し |
「自動生成キーの取出し」を参照してください。 |
|
結果セットの保持機能 |
「結果セットの保持機能」を参照してください。 |
この項では、Oracle JDBCドライバによってサポートされている次のJDBC 3.0機能について説明します。
JDBC 3.0の仕様はセーブポイントをサポートしており、トランザクション内でより細かい境界設定をすることができます。アプリケーションはトランザクション内にセーブポイントを設定して、セーブポイントより後に行われたすべての作業をロールバックすることができます。セーブポイントを使用することで、トランザクションの原子性が緩和されます。セーブポイントを持つトランザクションは、トランザクションのコンテキスト外部では1つの単位のように見えるという点で原子的ですが、トランザクション内で動作しているコードは部分的な状態を維持することができます。
|
注意: セーブポイントがサポートされるのは、ローカル・トランザクションのみです。グローバル・トランザクション内でセーブポイントを指定すると、SQLException例外が発生します。 |
セーブポイントを作成するには、java.sql.Savepointインスタンスを戻すConnection.setSavepointを使用します。
セーブポイントには名前がある場合とない場合があります。セーブポイントの名前を指定するには、setSavepointメソッドに文字列を指定します。名前が未指定の場合は、整数のIDが割り当てられます。名前の取出しにはgetSavepointNameメソッドを使用します。IDの取出しにはgetSavepointIdメソッドを使用します。
|
注意: 名前付けされていないセーブポイントから名前を取り出そうとしたり、名前付けされているセーブポイントからIDを取り出そうとしたりすると、SQLException例外がスローされます。 |
セーブポイントまでロールバックするには、Connection.rollback(Savepoint svpt)メソッドを使用します。解放されているセーブポイントまでロールバックしようとすると、SQLException例外がスローされます。
多くのデータベース・システムでは、行が挿入される際に一意のキー・フィールドが自動的に生成されます。Oracle Databaseでは、順序とトリガーにより、この機能が提供されます。JDBC 3.0には、自動生成キーの取出し機能が導入され、生成された値を取り出せるようになりました。JDBC 3.0では、自動生成キーの取出し機能をサポートするために、次のインタフェースが拡張されました。
java.sql.DatabaseMetaData
java.sql.Connection
java.sql.Statement
これらのインタフェースには、自動生成キーの取出しをサポートするメソッドが用意されています。ただし、この機能はINSERT文が処理される場合にのみサポートされます。その他のデータ操作言語(DML)文の処理では、自動生成キーの取出しは実施されません。
|
注意: Oracleのサーバー側内部ドライバでは、自動生成キーの取出し機能をサポートしていません。 |
キー列を明示的に指定しないと、Oracle JDBCドライバでは取り出す列を特定できません。Oracle JDBCドライバで自動生成キーを含む列を特定できるのは、列名または列索引の配列が使用されている場合です。ただし、int型のStatement.RETURN_GENERATED_KEYSフラグが使用されている場合、Oracle JDBCドライバではこれらの列を特定できません。int型フラグを使用して自動生成キーが戻るように指定した場合は、ROWID擬似列がキーとして戻ります。このROWIDは、ResultSetオブジェクトからフェッチして、他の列を取り出すために使用できます。
次のコードは、自動生成キーの取出しを示しています。
/** SQL statements for creating an ORDERS table and a sequence for generating the
* ORDER_ID.
*
* CREATE TABLE ORDERS (ORDER_ID NUMBER, CUSTOMER_ID NUMBER, ISBN NUMBER,
* DESCRIPTION NCHAR(5))
*
* CREATE SEQUENCE SEQ01 INCREMENT BY 1 START WITH 1000
*/
...
String cols[] = {"ORDER_ID", "DESCRIPTION"};
// Create a PreparedStatement for inserting a row into the ORDERS table.
OraclePreparedStatement pstmt = (OraclePreparedStatement)
conn.prepareStatement("INSERT INTO ORDERS (ORDER_ID, CUSTOMER_ID, ISBN, DESCRIPTION) VALUES (SEQ01.NEXTVAL, 101,
966431502, ?)", cols);
char c[] = {'a', '\u5185', 'b'};
String s = new String(c);
pstmt.setNString(1, s);
pstmt.executeUpdate();
ResultSet rset = pstmt.getGeneratedKeys();
...
前の例では、シーケンス( SEQ01)がORDER_ID列の値を生成するために作成されます。値は、1000から始まり、シーケンスが処理されて次の値が生成されるたびに1ずつ増加します。OraclePreparedStatementオブジェクトは、ORDERS表に行を挿入するために作成されています。
表3-2と表3-3では、Oracle独自のメソッドとJDBC 3.0標準メソッドとの間の変換を示しています。
表3-2 等価のBLOBメソッド
| Oracle独自のメソッド | JDBC 3.0標準メソッド |
|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
表3-3 等価のCLOBメソッド
| Oracle独自のメソッド | JDBC 3.0標準メソッド |
|---|---|
|
|
|
|
該当なし |
|
|
|
|
|
|
|
|
|
結果セットの保持機能は、JDBC 3.0から導入されました。この機能は、コミット操作が実行されるとき、ResultSetオブジェクトがオープンされているべきか、クローズされているべきかをアプリケーションが判断できるようにします。コミット操作は暗黙的でも明示的でもかまいません。
Oracle Databaseでサポートしているのは、HOLD_CURSORS_OVER_COMMITのみです。したがって、これが、Oracle JDBCドライバのデフォルト値です。保持機能を変更しようとすると必ず、SQLFeatureNotSupportedException例外がスローされます。
JDBC 4.0標準は、JDK 6以降のバージョンでサポートされています。Oracle Database 12cリリース1 (12.1)のJDBCドライバでは、JDBC 4.0標準がサポートされています。
|
注意:
|
Oracle Database 12cリリース1 (12.1)のJDBCドライバでは、次のような機能を利用できます。
ラッパー・パターンは、Javaアプリケーションで使用される一般的なコーディング・パターンで、データソース固有の従来のJDBC APIを超える機能を提供します。実際のリソースを表すプロキシ・クラス・インスタンスとしてラップされているリソースにアクセスする場合に、これらの拡張機能を使用する必要があることがあります。JDBC4.0では、リソース代理への直接アクセスを許可するために、プロキシによって表されるこれらのラップされたリソースにアクセスするための標準メカニズムを記述するWrapperインタフェースが導入されています。
Wrapperインタフェースでは、次の2つのメソッドが提供されています。
public boolean isWrapperFor(Class<?> iface) throws SQLException;
public <T> T unwrap(Class<T> iface) throws SQLException;
SQLデータを表すものを除く他のJDBC4.0インタフェースはすべてこのインタフェースを実装しています。これには、Connection、Statementとそのサブタイプ、ResultSetおよびメタデータ・インタフェースが含まれます。
JDBC 4.0標準で最も重要な更新内容の1つはSQL 2003標準で定義されたXMLデータ型のサポートです。現在、JDBCは、SQL/XMLデータベース・データ型をサポートするためのマッピング・インタフェースを提供しています(java.sql.SQLXML)。この新しいJDBCインタフェースは、XMLの、Javaネイティブのバインディングを定義し、それにより、データベースXMLデータの処理をより簡単、より効率的にしています。
|
注意:
|
java.sql.ConnectionインタフェースでcreateSQLXMLメソッドをコールすることによって、XMLのインスタンスを作成することができます。このメソッドは、空のXMLオブジェクトを戻します。
次に示すように、PreparedStatement、CallableStatementおよびResultSetインタフェースは拡張され、適切なgetterメソッドとsetterメソッドが用意されました。
PreparedStatement: メソッドsetSQLXMLが追加されました。
CallableStatement: メソッドgetSQLXMLおよびsetSQLXMLが追加されました。
ResultSet: メソッドgetSQLXMLが追加されました。
例
例3-1 SQLXMLデータへのアクセス
次の例は、StringからXMLのインスタンスを作成し、データベースにXMLデータを書き込み、データベースからXMLデータを取得する方法を示しています。
import java.sql.*;
import java.util.Properties;
import oracle.jdbc.pool.OracleDataSource;
public class SQLXMLTest
{
public static void main(String[] args)
{
Connection conn = null;
Statement stmt = null;
ResultSet rs = null;
PreparedStatement ps = null;
String xml = "<?xml version=\"1.0\"?>\n" +
"<oldjoke>\n" +
"<burns>Say <quote>goodnight</quote>, Gracie.</burns>\n" +
"<allen><quote>Goodnight, Gracie.</quote></allen>\n" +
"<applause/>\n" +
"</oldjoke>";
try
{
OracleDataSource ods = new OracleDataSource();
ods.setURL("jdbc:oracle:thin:@//localhost:5221/orcl");
ods.setUser("HR");
ods.setPassword("hr");
conn = ods.getConnection();
ps = conn.prepareStatement("insert into x values (?, ?)");
ps.setString(1, "string to string");
SQLXML x = conn.createSQLXML();
x.setString(xml);
ps.setSQLXML(2, x);
ps.execute();
stmt = conn.createStatement();
rs = stmt.executeQuery("select * from x");
while (rs.next())
{
x = rs.getSQLXML(2);
System.out.println(rs.getString(1) + "\n" + rs.getSQLXML(2).getString());
x.free();
}
rs.close();
ps.close();
}
catch (SQLException e){e.printStackTrace ();}
}
}
|
注意: 空のXMLを指定してsetterメソッドをコールすると、SQLExceptionがスローされます。getterメソッドが空のXMLを戻すことはありません。 |
JDBC 3.0では、SQLExceptionという単一の例外しかサポートされていません。ただし、エラーはカテゴリが多いので、区別すると便利です。この機能では、様々なカテゴリのエラーを特定するために、SQLExceptionクラスのサブクラスがサポートされています。永続エラーと一時エラーの切分けが、主要な切分けになります。永続エラーは、システムの正しい動作の結果であり、常に発生します。一時エラーは、タイムアウトなど、システムの一部で障害が発生した結果であり、再発しない場合もあります。
JDBC 4.0では、一時エラー、永続エラーおよびそれらエラーの様々なカテゴリを表現するために、例外が追加されています。
また、SQLExceptionクラスとそのサブクラスは、J2SE関連の例外機能をサポートするために機能拡張されています。
JDBC 4.0では、SQLのROWID値を表現するために、java.sql.RowIdデータ型がサポートされています。ResultSetインタフェースおよびCallableStatementインタフェースで定義されているgetterメソッドを使用すると、RowId値を取り出すことができます。開発者は、パラメータ化されたPreparedStatementの中でRowId値を使用して、RowIdオブジェクトのパラメータを設定したり、更新可能な結果セットの中で使用して、列を特定のRowId値に更新したりできます。
RowIdオブジェクトは、指定された行が削除されるまで有効です。RowIdオブジェクトは、次の場合にも有効なことがあります。
作成元トランザクションの期間中。
作成元セッションの期間中。
RowIdオブジェクトが永続的に有効である期間(未定義)。
DatabaseMetaData.getRowIdLifetimeメソッドをコールすると、RowIDオブジェクトの存続期間を確認できます。
JDBC 4.0では、BLOB、CLOBおよびNCLOBオブジェクトの作成をサポートするために、Connectionインタフェースが機能拡張されています。このインタフェースでサポートされているcreateBlob、createClobおよびcreateNClobメソッドを使用すると、Blob、ClobおよびNClobオブジェクトを作成できます。
作成されたLOB(Large OBject)にデータは含まれません。java.sql.Blob、java.sql.Clobおよびjava.sql.NClobインタフェースで使用可能なAPIをコールして、これらのオブジェクトにデータを追加または取得できます。これらのオブジェクトからは、内容の全体または一部を取り出すことができます。次のコードでは、BLOBオブジェクトのオフセット200の位置から100バイトのデータを取り出す方法を示しています。
... Connection con = DriverManager.getConnection(url, props); Blob aBlob = con.createBlob(); // Add data to the BLOB object. aBlob.setBytes(...); ... // Retrieve part of the data from the BLOB object. InputStream is = aBlob.getBinaryStream(200, 100); ...
setBlob、setClobおよびsetNClobメソッドを使用して、PreparedStatementオブジェクトにLOBを入力パラメータとして渡すこともできます。updateBlob、updateClobおよびupdateNClobメソッドを使用すると、更新可能結果セット内の列値を更新できます。
これらのLOBは一時LOBで、一時LOBを使用する必要がある場合に使用します。データベース内の記憶域を永続的にするには、これらのLOBを表に書き込む必要があります。
一時LOBは、作成元のトランザクションの期間中は少なくとも有効です。ただし、トランザクションの実行期間が長いと、メモリーの使用が保証されない場合があります。次のようにLOBのfreeメソッドをコールすると、LOBを解放できます。
... Clob aClob = con.createClob(); int numWritten = aClob.setString(1, val); aClob.free(); ...
JDBC 4.0では、各国語キャラクタ・セットの型にアクセスするためのNCHAR、NVARCHAR、LONGNVARCHARおよびNCLOBというJDBC型が導入されています。これらの型は、各国語キャラクタ・セットを使用して値がエンコードされる点を除き、CHAR、VARCHAR、LONGVARCHARおよびCLOB型に類似しています。
Oracle Database 12cリリース1 (12.1)のJDBCドライバでは、JDK 7を介してJDBC 4.1標準がサポートされています。この項では、今回のリリースでサポートされている次のメソッドについて説明します。
setClientInfoメソッドは、クライアント情報を提供するプロパティの値を設定します。このメソッドは、<namespace>.<keyname>の形式のキーを受け入れます。JDBCドライバでは、<namespace>.<keyname>の組合せをサポートしています。
|
注意: setClientInfoメソッドでは、他のネームスペースではOCSIDネームスペースをサポートしています。ただし、OCSIDネームスペースと他のネームスペースの使用方法には違いがあります。OCSIDネームスペースの場合、setClientInfoメソッドでは次のキーのみをサポートしています。
また、他のネームスペースに関連付けられた情報は単一のプロトコルを使用してネットワークで通信されますが、OCSIDネームスペースに関連付けられた情報は別のプロトコルを使用して通信されます。OCSIDネームスペースに使用されるプロトコルは、エンドツーエンドのメトリック値を送信するために、OCI Cライブラリと10gのThinドライバでも使用されます。 |
setClientInfoメソッドでは、Java権限oracle.jdbc.clientInfoをチェックします。このセキュリティ・チェックが失敗した場合、SecurityExceptionがスローされます。これは、<namespace>.*の形式の権限の名前パターンをサポートしています。setClientInfoメソッドはすべてのペアの設定またはクリアを行います。したがって、権限の名前にアスタリスク(*)を設定する必要があります。
setClientInfoメソッドはsetEndToEndMetricsおよびsetClientIdentifierメソッドとの下位互換性があり、DMSを使用してクライアント・タグを設定できます。
|
注意: Oracle Database 12cリリース1 (12.1)以降、setEndToEndMetricsメソッドは非推奨です。 |
多くのJavaアプリケーションにはデータベース接続機能がありませんが、その機能のかわりにデータベース・アクティビティを追跡する必要があります。このようなアプリケーションのために、Oracle Database 12cリリース1 (12.1)では、DBOPタグが導入されました。これは、アプリケーションがデータベースに明示的にアクセスできない場合に、アプリケーションのスレッドに関連付けることができます。DBOPタグは、DMS APIを起動してスレッドと関連付けられます。データベースへのアクティブな接続は不要です。スレッドが次のデータベース・コールを送信したとき、DMSはデータベース・コールとともに接続を介してこれらのタグを伝播します。追加のラウンドトリップの必要はありません。このように、アプリケーションは、アプリケーション・レイヤーのコードを分析しながら、そのアクティビティをデータベースの動作に関連付けることができます。DBOPタグは次の項目で構成されています。
データベースの動作の名前
実行ID
動作属性
setClientInfoメソッドでは、DBOPタグをサポートしています。setClientInfoメソッドは、データベース動作を監視するために、このタグの値を設定します。JDBCアプリケーションがデータベースに接続し、データベース・ラウンドトリップが行われると、データベース・アクティビティを追跡できます。たとえば、次のようにDBOPタグの値にfooを設定できます。
...
Connection conn = DriverManager.getConnection(myUrl, myUsername, myPassword);
conn.setClientInfo("E2E_CONTEXT.DBOP", "foo");
Statement stmt = conn.createStatement();
stmt.execute("select 1 from dual"); // DBOP tag is set after this
...
getObjectメソッドは、渡されたパラメータに基づいて、オブジェクトを取得します。Oracle Database 12cリリース1 (12.1)では、次の2つの新規getObjectメソッドをサポートしています。
方法1
<T> T getObject(int parameterIndex,
java.lang.Class<T> type)
throws SQLException
方法2
<T> T getObject(java.lang.String parameterName,
java.lang.Class<T> type)
throws SQLException
これらのメソッドでは、JDBC仕様に示された変換と表A-1に示された追加の変換をサポートしています。Oracle Database 12cリリース1 (12.1)のドライバでは、一部の追加クラスへの変換もサポートしています。これは、次の条件のいずれかが満たされている場合、1つ以上の静的なvalueOfメソッドを実装しています。
JDBC仕様または表A-1の他の変換が指定されていない。
type引数で、valueOfという名前の単一のパブリックで静的な引数メソッドを1つ以上定義している。
1つ以上のvalueOfメソッドがJDBC仕様または表A-1のためにサポートされている型の値である引数を取る。
今回のリリースのJDBCドライバは、JDBC仕様または表A-1で指定された型に値を変換してから、変換した値を引数として、対応するvalueOfメソッドをコールします。適切なvalueOfメソッドが複数ある場合、JDBCドライバはvalueOfメソッドを1つ選択します。この方法は指定されていません。
例
ResultSet rs = . . . ; Character c = rs.getObject(1, java.lang.Character.class);
Characterクラスは、次のvalueOfメソッドを定義します。
public static Character valueOf(char c);
表A-1では、NUMBERをcharに変換できることが示されています。したがって、ResultSetの最初の列がNUMBERである場合、getObjectメソッドはそのNUMBER値をcharに変換し、そのchar値をvalueOf(char)メソッドに渡し、結果のCharacterオブジェクトを戻します。