15 Oracleオブジェクト参照の使用

この章では、オブジェクト参照へのアクセスおよび操作を行う、標準Java Database Connectivity(JDBC)について説明します。

この項では、次の項目について説明します。

15.1 オブジェクト参照用Oracle拡張機能

Oracleでは、データベース・オブジェクトへの参照を使用できます。Oracle JDBCでは、次のオブジェクト参照がサポートされます。

  • SELECT句の列

  • INまたはOUTバインド変数

  • Oracleオブジェクトの属性

  • コレクション型オブジェクトの要素

SQLでは、オブジェクト参照(REF)は厳密に型指定されています。たとえば、EMPLOYEEオブジェクトへの参照は、REFのみではなく、EMPLOYEE REFとして定義されます。

オブジェクト参照を選択する場合は、オブジェクト本体でなく、オブジェクトへのポインタのみを取得することに注意してください。移植性を重視して、参照をjava.sql.Refインスタンスとしてインスタンス化するか、事前に作成したカスタムJavaクラスのインスタンスとしてインスタンス化して強い型指定の利点を取るか、両方の選択肢があります。オブジェクト参照のために使用されるカスタムJavaクラスは、カスタム参照クラスとして参照されるため、oracle.jdbc.OracleDataインタフェースを実装する必要があります。

結果セットまたはコール可能文オブジェクトを介してREFインスタンスを取得し、プリペアド文またはコール可能文オブジェクトを介して更新されたREFにインスタンスをデータベースに戻すことができます。REFクラスには、基礎となるオブジェクト属性値を取得および設定し、基礎となるオブジェクトのSQLベース型名を取得する機能があります。

カスタム参照クラスには、これと同じ機能が含まれている他に、強い型指定が適用されるという利点があります。この強い型指定により、実行時まで検出できないコーディング・エラーを、コンパイル時に発見できます。

ノート:

  • カスタム・オブジェクト・クラスに対してoracle.jdbc.OracleDataインタフェースを使用する場合は、対応するカスタム参照クラスにもOracleDataを使用します。ただし、カスタム・オブジェクト・クラスに対して標準java.sql.SQLDataインタフェースを使用する場合、参照に使用できるのは、弱いJava型のみです。SQLDataインタフェースは、SQLオブジェクト型のマッピング専用です。

  • JDBCアプリケーションでREFオブジェクトを作成して取り出すことができるのは、SQL文を実行した場合のみです。REFオブジェクトを作成して取り出すためのJDBC固有の機能はありません。

  • 配列はオブジェクトの同様に構造化型ですが、参照できません。

15.2 オブジェクト参照の取出しと引渡し

この項では、オブジェクト参照の取出しと引渡しを行うJDBC機能を説明します。内容は次のとおりです。

15.2.1 結果セットからのオブジェクト参照の取出し

オブジェクト参照を取り出す方法を示すために、次の例では、最初に、Oracleオブジェクト型ADDRESSを定義し、次にPEOPLE表でこのオブジェクト型を参照します。

create type ADDRESS as object
   (street_name     VARCHAR2(30),
    house_no        NUMBER);

create table PEOPLE 
    (col1 VARCHAR2(30),
     col2 NUMBER,
     col3 REF ADDRESS);

ADDRESSオブジェクト型には、street nameとhouse numberという2つの属性があります。PEOPLE表には、文字データ用の列、数値データ用の列、およびADDRESSオブジェクトへの参照を含む列が設定されています。

オブジェクト参照を取り出すには、次のステップに従ってください。

  1. 標準SQL SELECT文を使用して、データベース表のREF列から参照を取り出します。
  2. getRefを使用して、結果セットからAddress参照を取り出し、OracleRefインスタンスに格納します。
  3. AddressをSQLオブジェクト型のADDRESSに対応するJavaカスタム・クラスに変換します。
  4. JavaクラスAddressとSQL型ADDRESS間の対応を、型マップに追加します。
  5. getObjectメソッドを使用して、Address参照の内容を取り出します。出力をAddressにキャストします。

また、PEOPLEデータベース表の定義については、この項の始めの説明を参照してください。前述のステップを実行するコードは、Addressを型マップに追加するステップを除いて、次のようになります。

ResultSet rs = stmt.executeQuery("SELECT col3 FROM PEOPLE"); 
while (rs.next())
{
   OracleRef ref = rs.getRef(1);
   Address a = (Address)ref.getObject();
}

ノート:

前述のコードで、stmtはあらかじめ定義されている文オブジェクトです。

15.2.2 オブジェクト参照のコール可能文からの取出し

オブジェクト参照をPL/SQLブロックのOUTパラメータとして取り出すには、OUTパラメータのバインド型を登録する必要があります。

  1. 次のように、コール可能文をOracleCallableStatementにキャストします。
    OracleCallableStatement ocs = 
       (OracleCallableStatement)conn.prepareCall("{? = call func()}");
    
  2. 次の形式のregisterOutParameterメソッドを使用して、OUTパラメータを登録します。
    ocs.registerOutParameter (int param_index, int sql_type, String sql_type_name);
    

    param_indexはパラメータ索引、sql_typeはSQL型コードです。sql_type_nameは、この参照が使用される構造化オブジェクト型の名前です。たとえば、OUTパラメータがADDRESSオブジェクトに対する参照の場合、ADDRESSは渡されるsql_type_nameです。

  3. 次のように、コールを実行します。
    ocs.execute();

15.2.3 オブジェクト参照のプリペアド文への引渡し

オブジェクト参照をプリペアド文に渡す方法は、他のSQL型を渡す場合と同様です。プリペアド文のオブジェクトのsetObjectメソッドまたはsetREFメソッドを使用します。

次のプリペアド文を使用し、ROWIDに基づいてアドレス参照を更新します。

PreparedStatement pstmt = 
   conn.prepareStatement ("update PEOPLE set ADDR_REF = ? where ROWID = ?");
pstmt.setRef (1, addr_ref);
    pstmt.setRowId (2, rowid);

15.3 オブジェクト値に対する、オブジェクト参照を介したアクセスと更新

RefオブジェクトのsetObjectメソッドを使用すると、データベースにあるオブジェクトの値をオブジェクト参照から更新できます。このためには、最初に、データベース・オブジェクトに対する参照を取り出し、データベース・オブジェクトに対応するJavaオブジェクトを作成する必要があります。

たとえば、次のコードのように、「オブジェクト参照の取出しと引渡し」のコードを使用して、データベースのADDRESSオブジェクトへの参照を取り出せます。

ResultSet rs = stmt.executeQuery("SELECT col3 FROM PEOPLE"); 
if (rs.next())
{
   Ref ref = rs.getRef(1);
   Address a = (Address)ref.getObject();
}

次に、データベースのADDRESSオブジェクトに対応するJavaのAddressオブジェクトを作成できます。次のように、RefインタフェースのsetObjectメソッドを使用して、データベース・オブジェクトの値を設定します。

Address addr = new Address(...);
ref.setObject(addr);

この例では、setValueメソッドによりデータベースのADDRESSオブジェクトが即時更新されます。