18 JDBC RowSet

この章の構成は、次のとおりです。

18.1 JDBC RowSetの概要

RowSetは、Java Database Connectivity(JDBC)の結果セットまたは表形式データソースの一連の行をカプセル化するオブジェクトです。RowSetは、JavaBeansなどのコンポーネント・ベースの開発モデル、一連の標準プロパティおよびイベント通知メカニズムをサポートしています。

RowSetsは、JDBC 2.0で、オプションのパッケージによって導入されました。ただし、RowSetsの実装はJDBC RowSet Implementations Specification(JSR-114)で標準化され、Java Platform, Standard Edition(Java SE)5.0以降、オプションでないパッケージとして利用できます。Java SE 6.0 RowSetsには、RowIdや各国語文字セットなどのような機能をサポートするAPIがより多く含まれます。Java SE Javadocには、JDBC RowSetの実装のための、標準インタフェースと基本クラスに関する情報が含まれています。

JSR-114仕様には、次の5種類のRowSetの実装詳細が記載されています。

  • CachedRowSet

  • JdbcRowSet

  • WebRowSet

  • FilteredRowSet

  • JoinRowSet

Oracle JDBCは、5種類のRowSetすべてを、oracle.jdbc.rowsetパッケージにあるインタフェースおよびクラスを介してサポートしています。Oracle Database 11gリリース1以降、サーバー側ドライバにRowSetsサポートが追加されました。このため、Oracle Database 11gリリース1からは、すべてのOracle JDBCドライバの型にわたり、RowSetサポートは均一です。標準のOracle JDBC Java Archive(JAR)ファイル、たとえば、ojdbc6.jarおよびojdbc7.jarにはoracle.jdbc.rowsetパッケージが含まれます。

ノート:

  • 接尾辞名の異なる他のJARファイル、たとえば、ojdbc6_g.jarおよびojdbc6dms.jarにも、oracle.jdbc.rowsetパッケージが含まれます。

  • Oracle Database 10gリリース2では、実装クラスはojdbc14.jarファイルにパッケージ化されていました。

  • Oracle Database 10gリリース2より前では、実装クラスはojdbc12.jarファイルにパッケージ化されていました。

  • Oracle Database 11gリリース1より前は、RowSetsサポートはサーバー側ドライバでは利用できませんでした。

ノート:

Oracle Database 10gリリース2 (10.2)では、このパッケージは標準Oracle JDBC JARファイル(classes12.jarojdbc5.jarおよびojdbc6.jar)に含まれています。Oracle Database 10gリリース2 (10.2)より前では、row set実装クラスはocrs12.jarファイルにパッケージ化されていました。

Oracle RowSet実装を使用するには、必要なRowSet型のパッケージからoracle.jdbc.rowsetパッケージ全体、または特定のクラスおよびインタフェースをインポートする必要があります。またクライアント側では、CLASSPATH環境変数にojdbc6.jarまたはojdbc7.jarなどのOracle JARファイルをインクルードする必要があります。

この項の内容は次のとおりです。

18.1.1 RowSetのプロパティ

javax.sql.RowSetインタフェースは、単一のインタフェースでデータソースのデータにアクセスするために変更できるJavaBeansプロパティ一式を提供します。プロパティには、たとえば接続文字列、ユーザー名、パスワード、接続の種類および問合せ文字列があります。

関連項目:

プロパティおよびプロパティの説明の完全なリストは、http://docs.oracle.com/javase/1.5.0/docs/api/javax/sql/RowSet.htmlのJava2 Platform, Standard Edition (J2SE)のJavadocを参照

このインタフェースは、プロパティ値の設定および取出しに必要な標準アクセッサ・メソッドを提供します。次のコードは、一部のRowSetプロパティを設定します。

...
rowset.setUrl("jdbc:oracle:oci:@");
rowset.setUsername("HR");
rowset.setPassword("hr");
rowset.setCommand("SELECT employee_id, first_name, last_name, salary FROM employees");
...

この例では、URL、ユーザー名、パスワードおよびSQL問合せが、従業員番号、従業員名および全従業員の給与をRowSetオブジェクト内に取り出すためのRowSetプロパティとして設定されています。

18.1.2 イベントおよびイベント・リスナー

RowSetはJavaBeansイベントをサポートします。RowSetインタフェースは、次のタイプのイベントをサポートします。

  • cursorMoved

    このイベントはカーソルが移動するたびに生成されます。たとえば、nextメソッドまたはpreviousメソッドがコールされると生成されます。

  • rowChanged

    このイベントは、RowSetに行が挿入されるか、RowSetの行が更新されるか、またはRowSetから行が削除されると生成されます。

  • rowSetChanged

    このイベントは、RowSet全体が作成または変更されると生成されます。たとえば、executeメソッドがコールされると生成されます。

アプリケーション・コンポーネントでは、RowSetリスナーを実装し、これらのRowSetイベントをリスニングして、イベントの発生時に必要な操作を実行できます。これらのイベントに関係のあるアプリケーション・コンポーネントの場合は、標準のjavax.sql.RowSetListenerインタフェースを実装し、RowSetオブジェクトにこれらのリスナー・オブジェクトを登録する必要があります。リスナーの登録にはRowSet.addRowSetListenerメソッドを使用し、登録を解除するにはRowSet.removeRowSetListenerメソッドを使用します。複数のリスナーを同じRowSetオブジェクトに登録できます。

次のコードは、RowSetリスナーを登録します。

 ...
 MyRowSetListener rowsetListener = new MyRowSetListener ();
 // adding a rowset listener
 rowset.addRowSetListener (rowsetListener);
 ...

次のコードは、リスナーを実装します。

 public class MyRowSetListener implements RowSetListener
  {
    public void cursorMoved(RowSetEvent event)
    {
      // action on cursor movement
    }
 
    public void rowChanged(RowSetEvent event)
    {
      // action on change of row
    }
 
    public void rowSetChanged(RowSetEvent event)
    {
      // action on changing of rowset
    }
  }// end of class MyRowSetListener

選択されたイベントのみを処理するアプリケーションの場合、すべてのイベント処理メソッド用の空の実装を持つ抽象クラスであるoracle.jdbc.rowset.OracleRowSetListenerAdapterクラスを使用することにより、必要なイベント処理メソッドのみを実装することができます。次のコードでは、rowSetChangedイベントのみが処理され、残りのイベントは処理されません。

 ...
 rowset.addRowSetListener(new oracle.jdbc.rowset.OracleRowSetListenerAdapter ()
    {
      public void rowSetChanged(RowSetEvent event)
      {
        // your action for rowSetChanged
      }
    }
  );
 ...

18.1.3 コマンド・パラメータおよびコマンド実行

RowSetオブジェクトのcommandプロパティは、通常はSQL問合せ文字列を表し、処理時に実際のデータをRowSetオブジェクトに移入します。通常のJDBC処理と同様に、この問合せ文字列は入力やバインド・パラメータをとることができます。javax.sql.RowSetインタフェースにも、このSQL問合せに入力パラメータを設定するメソッドがあります。必要な入力パラメータが設定された後でSQL問合せが処理され、基礎となるデータソースのデータをRowSetオブジェクトに移入できます。次のコードは、この単純な手順を示しています。

 ...
  rowset.setCommand("SELECT first_name, last_name, salary FROM employees WHERE employee_id = ?");
  // setting the employee number input parameter for employee named "Douglas"
  rowset.setInt(1, 199);
  rowset.execute();
  ...

前述の例では、従業員番号199が、RowSetオブジェクトのcommandプロパティで指定されたSQL問合せの入力パラメータまたはバインド・パラメータとして設定されています。SQL問合せが処理されると、RowSetオブジェクトは、従業員番号199の従業員の従業員名と給与情報で満たされます。

18.1.4 RowSetの横断について

javax.sql.RowSetインタフェースは、java.sql.ResultSetインタフェースを拡張します。そのため、RowSetインタフェースでは、カーソル移動および位置指定の各メソッドがResultSetインタフェースから継承され、RowSetオブジェクト内のデータの横断に使用されます。継承されるメソッドの中には、absolutebeforeFirstafterLastnextおよびpreviousがあります。

RowSetインタフェースは、データを取得および更新するためのResultSetインタフェースと同じように使用できます。RowSetインタフェースでは、オプションでスクロール可能および更新可能な結果セットを実装できます。ResultSetインタフェースに含まれるすべてのフィールドおよびメソッドが、RowSetに実装されます。

ノート:

java.sql.ResultSetインタフェースのスクロール可能で更新可能なプロパティは、ResultSetのOracle実装でも提供されます。

次のコードは、RowSetをスクロールする方法を示します。

/**
 *  Scrolling forward, and printing the empno in 
 *  the order in which it was fetched.
 */
...
rowset.setCommand("SELECT empno, ename, sal FROM emp");
rowset.execute();
...
// going to the first row of the rowset
rowset.beforeFirst ();
while (rowset.next ())
  System.out.println ("empno: " +rowset.getInt (1));

前述のコードでは、beforeFirstメソッドによって、カーソル位置がRowSetの最初の行の前に初期化されます。行は、nextメソッドを使用して前方方向に取り出されます。

次のコードは、RowSetを逆方向にスクロールする方法を示します。

/**
 *  Scrolling backward, and printing the empno in 
 *  the reverse order as it was fetched.
 */
//going to the last row of the rowset
rowset.afterLast ();
while (rowset.previous ())
  System.out.println ("empno: " +rowset.getInt (1));

前述の例では、RowSetの最後の行の後にカーソル位置が初期化されます。行は、RowSetpreviousメソッドを使用して逆方向に取り出されます。

行の挿入、更新および削除は、結果セット機能と同様に行セット機能でもサポートされます。行セットを更新可能にするには、setReadOnly(false)およびacceptChangesの各メソッドをコールする必要があります。

次のコードは、行セットの5番目の位置に1行を挿入します。

...
/**
  * Make rowset updatable
  */
rowset.setReadOnly (false); 
/**
 * Inserting a row in the 5th position of the rowset.
 */
// moving the cursor to the 5th position in the rowset
if (rowset.absolute(5))
{
  rowset.moveToInsertRow ();
  rowset.updateInt (1, 193);
  rowset.updateString (2, "Smith");
  rowset.updateInt (3, 7200);

  // inserting a row in the rowset
  rowset.insertRow ();

  // Synchronizing the data in RowSet with that in the database.
  rowset.acceptChanges ();
}
...

前述の例では、パラメータ5が指定されたabsoluteメソッドをコールすることにより、RowSetの5番目の位置にカーソルが移動し、moveToInsertRowメソッドをコールすることにより、RowSetに新しい行を挿入するための場所が作成されます。新しく作成された行を更新するには、updateXXXメソッドを使用します。行のすべての列が更新されると、insertRowがコールされ、そのRowSetが更新されます。変更はacceptChangesメソッドを使用してコミットします。

18.2 CachedRowSetについて

CachedRowSetは、行がキャッシュされ、切断されている(つまり、データベースとのアクティブ接続を持たない)RowSetです。oracle.jdbc.rowset.OracleCachedRowSetクラスは、CachedRowSetのOracle実装です。これは標準のリファレンス実装と相互運用できます。ojdbc6.jarファイルおよびojdbc7.jarファイルのOracleCachedRowSetクラスは、標準のJSR-114インタフェースjavax.sql.rowset.CachedRowSetを実装します。

次のコードでは、OracleCachedRowSetオブジェクトを作成し、プロパティとしてRowSetオブジェクトの接続URL、ユーザー名、パスワードおよびSQL問合せを設定します。RowSetオブジェクトには、executeメソッドを使用してデータが移入されます。executeメソッドを処理した後、java.sql.ResultSetオブジェクトとしてRowSetオブジェクトを使用できるため、データの取得、スクロール、挿入、削除または更新を実行できます。

...
RowSet rowset = new OracleCachedRowSet();
rowset.setUrl("jdbc:oracle:oci:@");
rowset.setUsername("HR");
rowset.setPassword("hr");
rowset.setCommand("SELECT employee_id, first_name, last_name, salary FROM employees");
rowset.execute();
while (rowset.next ())
{
  System.out.println("employee_id: " +rowset.getInt (1));
  System.out.println("first_name: " +rowset.getString (2));
  System.out.println("last_name: " +rowset.getString (3));
  System.out.println("sal: "   +rowset.getInt (4));
}
...

問合せによりCachedRowSetオブジェクトにデータを移入するには、次のステップを実行します。

  1. OracleCachedRowSetをインスタンス化します。

  2. Url(接続URL)、UsernamePasswordおよびCommand(問合せ文字列で、RowSetオブジェクトのプロパティ)を設定します。接続型を設定することもできますが、それはオプションです。

  3. executeメソッドをコールして、CachedRowSetオブジェクトにデータを移入します。executeのコールにより、問合せセットがこのRowSetのプロパティとして実行されます。

    OracleCachedRowSet rowset = new OracleCachedRowSet ();
    rowset.setUrl ("jdbc:oracle:oci:@");
    rowset.setUsername ("HR");
    rowset.setPassword ("hr");
    rowset.setCommand ("SELECT employee_id, first_name, last_name, salary FROM employees");
    rowset.execute ();
    

populateメソッドを使用して、CachedRowSetオブジェクトに既存のResultSetオブジェクトを移入できます。これを行うには、次のステップを完了します。

  1. OracleCachedRowSetをインスタンス化します。

  2. すでに使用可能なResultSetオブジェクトをpopulateメソッドに渡して、RowSetオブジェクトにデータを移入します。

    // Executing a query to get the ResultSet object.
    ResultSet rset = pstmt.executeQuery ();
    
    OracleCachedRowSet rowset = new OracleCachedRowSet ();
    // the obtained ResultSet object is passed to the populate method
    // to populate the data in the rowset object.
    rowset.populate (rset);
    

前述の例では、問合せを実行してResultSetオブジェクトを取得し、そのResultSetオブジェクトがCachedRowSetオブジェクトのpopulateメソッドに渡されて、結果セットの内容がCachedRowSetに移入されています。

ノート:

既存のResultSetオブジェクトをCachedRowSetオブジェクトへのデータの移入に使用する場合には、プロパティが適用される接続または結果セットがすでに作成されているため、トランザクションの分離や結果セットの同時実行性モードなどの接続プロパティおよびバインド・プロパティを設定することはできません。

次のコードは、OracleCachedRowSetオブジェクトをファイルに対してシリアライズしてから取得します。

// writing the serialized OracleCachedRowSet object
{
  FileOutputStream fileOutputStream = new FileOutputStream("emp_tab.dmp");
  ObjectOutputStream ostream = new ObjectOutputStream(fileOutputStream);
  ostream.writeObject(rowset);
  ostream.close();
  fileOutputStream.close();
}

// reading the serialized OracleCachedRowSet object
{
  FileInputStream fileInputStream = new FileInputStream("emp_tab.dmp");
  ObjectInputStream istream = new ObjectInputStream(fileInputStream);
  RowSet rowset1 = (RowSet) istream.readObject();
  istream.close();
  fileInputStream.close();
}

前述のコードでは、emp_tab.dmpファイル用にFileOutputStreamオブジェクトがオープンされ、データを移入されたOracleCachedRowSetオブジェクトがObjectOutputStreamを使用してこのファイルに書き込まれます。シリアライズされたOracleCachedRowSetオブジェクトは、FileInputStreamおよびObjectInputStreamオブジェクトを使用して取り出されます。

InputStreamOutputStream、バイナリ・ラージ・オブジェクト(BLOB)およびキャラクタ・ラージ・オブジェクト(CLOB)などの非シリアライズ形式のデータは、OracleCachedRowSetによってシリアライズされます。また、OracleCachedRowSetsは独自のメタデータを実装するため、追加のラウンドトリップを必要とせずに取得できます。次のコードは、RowSetのメタデータを取得する方法を示します。

...
ResultSetMetaData metaData = rowset.getMetaData();
int maxCol = metaData.getColumnCount();
for (int i = 1; i <= maxCol; ++i)
   System.out.println("Column (" + i +") " + metaData.getColumnName(i));
...

OracleCachedRowSetクラスはシリアライズ可能なので、Remote Method Invocation(RMI)の場合と同様に、ネットワークや別のJava仮想マシン(JVM)の間で渡すことができます。OracleCachedRowSetクラスにデータが移入されると、任意のJVMまたはJDBCドライバを使用していない環境での移動が可能になります。RowSetにデータをコミットするには、JDBCドライバがインストールされている必要があります。

データを取得して、OracleCachedRowSetクラスでそれにデータを移入する処理の全体はサーバーで実行され、データを移入されたRowSetは、RMIやEnterprise Java Beans(EJB)などの適切なアーキテクチャを使用してクライアントに渡されます。クライアントは、取得、スクロール、挿入、更新および削除などすべての操作を、RowSet上で、データベースに接続しないで実行できます。データベースにデータがコミットされる場合は常に、RowSet内のデータとデータベース内のデータを同期させるacceptChangesメソッドがコールされます。このメソッドはJDBCドライバを利用するため、JVM環境にJDBC実装が含まれる必要があります。このアーキテクチャは、携帯情報端末(PDA)などのThinクライアントが関係するシステムに適しています。

CachedRowSetオブジェクトにデータを移入すると、このオブジェクトをResultSetオブジェクト、またはRMIやその他の適切なアーキテクチャを使用してネットワークを通じて渡すことが可能な他のオブジェクトとして使用できます。

CachedRowSetには、この他に次のような主要機能があります。

  • RowSetのクローニング

  • RowSetのコピーの作成

  • RowSetの共有コピーの作成

CachedRowSetの制約事項

OracleCachedRowSetはシリアライズ可能なので、更新可能な結果セットに適用される、シリアライズ以外のすべての制約をここで適用できます。SQL問合せには、次の制約があります。

  • データベース内の1つの表のみを参照できます。

  • 結合操作は含まれません。

  • 参照先の表の主キーを選択します。

また、新しい行を挿入するには、SQL問合せが次の条件を満たしている必要があります。

  • 基礎となる表のNULL化可能でない列すべてを選択します。

  • デフォルト値のないすべての列を選択します。

    ノート:

    データはすべてメモリーにキャッシュされるため、CachedRowSetには大量のデータを格納できません。したがって、大量のデータを戻す可能性のあるOracleCachedRowSetを問合せで使用しないことをお薦めします。

結果セットのトランザクションの分離や同時実行性モードなど接続プロパティは、RowSetへのデータの移入後には設定できません。このプロパティは、データを取り出した後には接続に適用できないためです。

18.3 JdbcRowSetについて

JdbcRowSetは、ResultSetオブジェクトをラップするRowSetです。これは、接続RowSetであり、JavaBeanインタフェース形式のJDBCインタフェースを提供します。JdbcRowSetのOracle実装は、oracle.jdbc.rowset.OracleJDBCRowSetです。ojdbc6.jarファイルおよびojdbc7.jarファイルのOracleJDBCRowSetクラスは、標準のJSR-114インタフェースjavax.sql.rowset.JdbcRowSetを実装します。

表18-1は、JdbcRowSetインタフェースとCachedRowSetインタフェースの違いを示しています。

表18-1 JDBCのRowSetとCachedRowSetの比較

RowSetのタイプ シリアライズ可能 データベースへの接続 JVM内での移動が可能 データベースに対するデータの同期化 JDBCドライバの存在

JDBC

あり

あり

なし

なし

あり

キャッシュ

あり

なし

あり

あり

なし

JdbcRowSetは接続されているRowSetで、データベースへのライブ接続を持ち、JdbcRowSet上のすべてのコールは、JDBC接続、文または結果セットのマッピング・コールに反映されます。CachedRowSetは、開いているデータベースへの接続をいっさい持ちません。

JdbcRowSetではJDBCドライバが存在する必要があるのに対して、CachedRowSetの場合は、操作時にJDBCドライバが存在する必要はありません。ただし、JdbcRowSetおよびCachedRowSetでは、RowSetへのデータ移入時とRowSetの変更をコミットするときには、JDBCドライバが必要です。

次のコードは、JdbcRowSetの使用方法を示します。

...
RowSet rowset = new OracleJDBCRowSet();
rowset.setUrl("java:oracle:oci:@");
rowset.setUsername("HR");
rowset.setPassword("hr");
rowset.setCommand("SELECT empno, ename, sal FROM emp");
rowset.execute();
while (rowset.next())
{
  System.out.println("empno: " + rowset.getInt(1));
  System.out.println("ename: " + rowset.getString(2));
  System.out.println("sal: " + rowset.getInt(3));
}
...

前述の例では、接続URL、ユーザー名、パスワードおよびSQL問合せがRowSetオブジェクトのプロパティとして設定され、SQL問合せがexecuteメソッドを使用して処理され、行がRowSetオブジェクトに移入されたデータを横断して取得され出力されます。

18.4 WebRowSetについて

WebRowSetは、CachedRowSetの拡張機能です。このRowSetは一連のフェッチされる行または表データを表し、データソースとのアクティブな接続を保持せずに、各層およびコンポーネント間で渡すことができます。WebRowSetインタフェースは、結果セットの生成と使用をサポートし、結果セットとデータソースとの同期をExtensible Markup Language(XML)形式および接続切断方式の両方でサポートします。これにより、層と層をまたがり、またインターネット・プロトコルを介して、結果セットを移送できます。

WebRowSetのOracle実装は、oracle.jdbc.rowset.OracleWebRowSetです。このクラスは、ojdbc6.jarファイルおよびojdbc7.jarファイル内にあり、標準のJSR-114インタフェースjavax.sql.rowset.WebRowSetを実装します。このクラスは、oracle.jdbc.rowset.OracleCachedRowSetクラスも拡張します。OracleWebRowSetクラスは、OracleCachedRowSetクラスで使用可能なメソッドの他に、次のメソッドも提供します。

  • public OracleWebRowSet() throws SQLException
    

    これは、OracleWebRowSetオブジェクトの作成に使用するコンストラクタであり、OracleCachedRowSetオブジェクトのデフォルト値、デフォルトのOracleWebRowSetXmlReaderおよびデフォルトのOracleWebRowSetXmlWriterによって初期化されます。

  • public void writeXml(java.io.Writer writer) throws SQLException
    public void writeXml(java.io.OutputStream ostream) throws SQLException
    

    これらのメソッドは、OracleWebRowSetオブジェクトを、提供されたWriterまたはOutputStreamオブジェクトにJSR-114 XMLスキーマ準拠のXML形式で書き込みます。RowSetデータの他に、RowSetのプロパティとメタデータも書き込まれます。

  • public void writeXml(ResultSet rset, java.io.Writer writer) throws SQLException
    public void writeXml(ResultSet rset, java.io.OutputStream ostream) throws SQLException
    

    これらのメソッドは、OracleWebRowSetオブジェクトを作成し、そのオブジェクトに指定したResultSetオブジェクトのデータを移入し、提供されたWriterまたはOutputStreamオブジェクトにJSR-114 XMLスキーマ準拠のXML形式で書き込みます。

  • public void readXml(java.io.Reader reader) throws SQLException
    public void readXml(java.io.InputStream istream) throws SQLException
    

    これらのメソッドは、提供されたReaderまたはInsputStreamオブジェクトを使用して、OracleWebRowSetオブジェクトをJSR-114 XMLスキーマ準拠のXML形式で読み取ります。

Oracle WebRowSet実装は、Java API for XML Processing (JAXP) 1.2をサポートしています。Simple API for XML (SAX) 2.0とDocument Object Model (DOM) JAXPのどちらに準拠しているXMLパーサーもサポートされます。WebRowSetの現在のJSR-114 W3C XMLスキーマに準拠します。

readXml(...)メソッドを使用するアプリケーションの場合は、メソッドのコール前に、次の2つの標準JAXPシステム・プロパティのいずれかを設定する必要があります。

  • javax.xml.parsers.SAXParserFactory

    このプロパティは、SAXパーサー用です。

  • javax.xml.parsers.DocumentBuilderFactory

    このプロパティは、DOMパーサー用です。

次のコードでは、XML形式での書込みおよび読取り両方にOracleWebRowSetを使用します。

import java.sql.*;
import java.io.*;
import oracle.jdbc.rowset.*;

...
String url = "jdbc:oracle:oci8:@";

Connection conn = DriverManager.getConnection(url,"HR","hr");
Statement stmt = conn.createStatement();
ResultSet rset = stmt.executeQuery("select * from employees");

// Create an OracleWebRowSet object and populate it with the ResultSet object
OracleWebRowSet wset = new OracleWebRowSet();
wset.populate(rset);

try
{
  // Create a java.io.Writer object
  FileWriter out = new FileWriter("xml.out");
  
  // Now generate the XML and write it out
  wset.writeXml(out);
}
catch (IOException exc)
{
  System.out.println("Couldn't construct a FileWriter");
}
System.out.println("XML output file generated.");

// Create a new OracleWebRowSet for reading from XML input
OracleWebRowSet wset2 = new OracleWebRowSet();

// Use Oracle JAXP SAX parser
System.setProperty("javax.xml.parsers.SAXParserFactory","oracle.xml.jaxp.JXSAXParserFactory");

try
{
  // Use the preceding output file as input
  FileReader fr = new FileReader("xml.out");
  
  // Now read XML stream from the FileReader
  wset2.readXml(fr);
}
catch (IOException exc)
{
  System.out.println("Couldn't construct a FileReader");
}
...

ノート:

前述のコードでは、スキーマの妥当性チェックをサポートするOracle SAX XMLパーサーを使用しています。

18.5 FilteredRowSetについて

FilteredRowSetは、WebRowSetの拡張機能であり、プログラム内容のフィルタリングに必要なプログラム・サポートを提供します。これにより、問合せの指定および関連処理に要するオーバーヘッドを回避できます。FilteredRowSetのOracle実装は、oracle.jdbc.rowset.OracleFilteredRowSetです。ojdbc7.jarファイルのOracleFilteredRowSetクラスは、標準のJSR-114インタフェースjavax.sql.rowset.FilteredRowSetを実装します。

OracleFilteredRowSetクラスは、次の新しいメソッドを定義します。

  • public Predicate getFilter();
    

    このメソッドは、OracleFilteredRowSetオブジェクトでアクティブなフィルタリング基準を定義するPredicateオブジェクトを戻します。

  • public void setFilter(Predicate p) throws SQLException;
    

    このメソッドは、Predicateオブジェクトをパラメータとして取ります。Predicateオブジェクトは、OracleFilteredRowSetオブジェクトに適用するフィルタリング基準を定義します。このメソッドでは、SQLException例外が発生します。

ノート:

FilteredRowSet機能に対してojdbc5.jarおよびojdbc6.jarのかわりにclasses12.jarを使用している場合、PredicateのかわりにOraclePredicateを使用します。Oracle固有のoracle.jdbc.rowset.OraclePredicateインタフェースは、Predicateと同等です。このインタフェースは、JSR-114パッケージを使用できない場合に使用します。

OracleFilteredRowSetオブジェクトに設定される条件は、参照できる行のセットを取得するためにオブジェクト内の行すべてに適用するフィルタリング基準を定義します。また、行の挿入、削除および変更に適用する基準も定義します。設定されたフィルタリング基準は、OracleFilteredRowSetオブジェクトの参照および更新すべてに適用されるゲーティング・メカニズムとして機能します。OracleFilteredRowSetオブジェクトを更新しようとすると、フィルタリング基準に違反するため、SQLException例外が発生します。

OracleFilteredRowSetオブジェクトに設定されているフィルタリング基準を変更するには、新しいPredicateオブジェクトを適用します。新しい基準は即時にオブジェクトに適用されるため、適用以後の参照および更新では、すべてこの新しい基準に準拠する必要があります。新しいフィルタリング基準を適用できるのは、OracleFilteredRowSetオブジェクトへの参照がない場合のみです。

オブジェクトに設定されたフィルタリング基準の範囲外の行は、そのフィルタリング基準が削除されるか、新しいフィルタリング基準が適用されるまで変更できません。また、このオブジェクトの同期化を続行しても、データソースと同期化される行は、フィルタリング基準の範囲内の行のみです。

次のコードは、OracleFilteredRowSetの使用例を示します。表test_tableに、NUMBER型のcol1およびcol2という2つの列があるものとします。この表からコードが取り出す行には、col150から100までの値、col2100から200までの値が含まれています。

フィルタリング基準を定義する条件を次に示します。

public class PredicateImpl implements Predicate
{
  private int low[];
  private int high[];
  private int columnIndexes[];
  
  public PredicateImpl(int[] lo, int[] hi, int[] indexes)
  {
    low = lo;
    high = hi;
    columnIndexes = indexes;
  }
  
  public boolean evaluate(RowSet rs)
  {
    boolean result = true;
    for (int i = 0; i < columnIndexes.length; i++)
    {
      int columnValue = rs.getInt(columnIndexes[i]);
      if (columnValue < low[i] || columnValue > high[i])
        result = false;
    }
    return result;
  }

// the other two evaluate(...) methods simply return true

}

前述のコードで定義した条件を使用して、OracleFilteredRowSetオブジェクトの内容を次のようにフィルタリングします。

...
OracleFilteredRowSet ofrs = new OracleFilteredRowSet();
int low[] = {50, 100};
int high[] = {100, 200};
int indexes[] = {1, 2};
ofrs.setCommand("select col1, col2 from test_table");

// set other properties on ofrs like usr/pwd ...
...
ofrs.execute();
ofrs.setPredicate(new PredicateImpl(low, high, indexes));

// this will only get rows with col1 in (50,100) and col2 in (100,200)
while (ofrs.next()) {...}
...

18.6 JoinRowSetについて

JoinRowSetは、WebRowSetの拡張機能であり、異なるRowSetの関連データで構成されています。データソースに接続していない状態では、切断されたRowSet間でSQL JOINを確立する標準的な方法はありません。JoinRowSetはこの問題に対応しています。JoinRowSetのOracle実装は、oracle.jdbc.rowset.OracleJoinRowSetクラスです。このクラスは、ojdbc7.jarファイル内にあり、標準のJSR-114インタフェースjavax.sql.rowset.JoinRowSetを実装します。

Joinableインタフェースを実装する任意の数のRowSetオブジェクトは、SQL JOINに関連付けることが可能な場合、JoinRowSetオブジェクトに追加できます。RowSetの5つのタイプはすべて、Joinableインタフェースをサポートします。Joinableインタフェースには、JOINを実行するときに使用する列(一致する列)を指定するためのメソッドがあります。

ノート:

JoinRowSet機能に対してojdbc5.jarおよびojdbc6.jarのかわりにclasses12.jarを使用している場合、JoinableのかわりにOracleJoinableを使用します。Oracle固有のoracle.jdbc.rowset.OracleJoinableインタフェースは、Joinableと同等です。このインタフェースは、JSR-114パッケージを使用できない場合に使用します。

一致する列は次の方法で指定できます。

  • setMatchColumnメソッドの使用

    このメソッドは、Joinableインタフェースで定義されます。RowSetオブジェクトをJoinRowSetオブジェクトに追加する前に、一致する列の設定に使用できるのは、このメソッドのみです。また、一致する列の再設定にいつでも使用できます。

  • addRowSetメソッドの使用

    このメソッドは、JoinRowSetでオーバーロードされます。このメソッドの5つの実装のうち4つは、一致する列をパラメータとして取ります。この4つのメソッドを使用して、RowSetオブジェクトをJoinRowSetオブジェクトに追加するときに、一致する列を設定または再設定できます。

OracleJoinRowSetは、継承されるメソッド以外に、次のメソッドを提供します。

  • public void addRowSet(Joinable joinable) throws SQLException;
    public void addRowSet(RowSet rowSet, int i) throws SQLException;
    public void addRowSet(RowSet rowSet, String s) throws SQLException;
    public void addRowSet(RowSet arowSet[], int an[]) throws SQLException;
    public void addRowSet(RowSet arowSet[], String as[]) throws SQLException;
    

    これらのメソッドを使用して、RowSetオブジェクトをOracleJoinRowSetオブジェクトに追加します。1つ以上のRowSetオブジェクトをOracleJoinRowSetオブジェクトに渡して追加できます。一致する列として設定する必要がある1つ以上の列の名前または索引を渡すこともできます。

  • public Collection getRowSets() throws SQLException;
    

    このメソッドは、OracleJoinRowSetに追加されたRowSetオブジェクトを取り出します。また、RowSetオブジェクトを含むjava.util.Collectionオブジェクトを戻します。

  • public String[] getRowSetNames() throws SQLException;
    

    このメソッドは、OracleJoinRowSetオブジェクトに追加されるRowSetオブジェクトの名前を含む文字列の配列を戻します。

  • public boolean supportsCrossJoin();
    public boolean supportsFullJoin();
    public boolean supportsInnerJoin();
    public boolean supportsLeftOuterJoin();
    public boolean supportsRightOuterJoin();
    

    これらのメソッドは、OracleJoinRowSetオブジェクトが、対応するJOIN型をサポートしているかどうかを示すブール値を戻します。

  • public void setJoinType(int i) throws SQLException;
    

    このメソッドを使用して、OracleJoinRowSetオブジェクトにJOIN型を設定します。このメソッドは、javax.sql.rowset.JoinRowSetインタフェースで定義されたJOIN型を指定する整数定数を取ります。

  • public int getJoinType() throws SQLException;
    

    このメソッドは、OracleJoinRowSetオブジェクトに設定されたJOIN型を示す整数値を戻します。このメソッドでは、SQLException例外が発生します。

  • public CachedRowSet toCachedRowSet() throws SQLException;
    

    このメソッドは、OracleJoinRowSetオブジェクトのデータを含むCachedRowSetオブジェクトを作成します。

  • public String getWhereClause() throws SQLException;
    

    このメソッドは、OracleJoinRowSetオブジェクトで使用されるWHERE句のSQLなどの記述を含む文字列を戻します。このメソッドでは、SQLException例外が発生します。

次のコードは、OracleJoinRowSetを使用して、2つの異なる表のデータを含む2つのRowSetで内部結合を実行します。結合されたRowSetには、2つの表で内部結合が実行された場合と同じデータが含まれます。表が2つあり、その一方はNUMBER型の2つの列Order_idおよびPerson_idを備えたOrder表、他方はNUMBER型の列Person_idVARCHAR2型の列Nameを備えたPerson表であるものとします。

...
// RowSet holding data from table Order
OracleCachedRowSet ocrsOrder = new OracleCachedRowSet();
...
ocrsOrder.setCommand("select order_id, person_id from order");
...
// Join on person_id column
ocrsOrder.setMatchColumn(2);
ocrsOrder.execute();

// Creating the JoinRowSet
OracleJoinRowSet ojrs = new OracleJoinRowSet();
ojrs.addRowSet(ocrsOrder);

// RowSet holding data from table Person
OracleCachedRowSet ocrsPerson = new OracleCachedRowSet();
...
ocrsPerson.setCommand("select person_id, name from person");
...
// do not set match column on this RowSet using setMatchColumn().
//use addRowSet() to set match column
ocrsPerson.execute();

// Join on person_id column, in another way
ojrs.addRowSet(ocrsPerson, 1);

// now we can go the JoinRowSet as usual
ojrs.beforeFirst();
while (ojrs.next())
System.out.println("order id = " + ojrs.getInt(1) + ", " + "person id = " +
ojrs.getInt(2) + ", " + "person's name = " + ojrs.getString(3));
...