目次へ

6.ResultSetを用いた更新処理 (Oracle8i)

この章では、ResultSetを用いた更新処理について説明します。OracleのThinドライバで説明します。

またこの機能を日本語のデータを対象に扱う場合には、Oracle8iのJDBCドライバの代わりにOracle 9iのJDBCドライバ(http://otn.oracle.co.jp/software/tech/java/jdbc/index.htmlからダウンロード可能)を使用するようにして下さい。ThinドライバについてはOracle7以上の大半のDBをサポートしていますのでOracle8iでも利用可能です。ただしOCIドライバについてはOracle Clientのバージョンに依存しますので、Oracle8iで利用する事はできません。注意してください。

6.1.カーソルの種類

「java.sql.Result」の実体は、クエリー文の結果セットを指し示すカーソルです。このカーソルの種類によって「ResultSet」で行える機能が異なってきます。カーソルの種類の指定は、「Connection」から「createStatement」「prepareStatement」を実行する際に行います。

Connection conn=DriverManager.getConnection("jdbc:oracle:thin:@dbserver:1521:oracle",
                                            "scott","tiger");
Statement statement=conn.createStatement(ResultSet.TYPE_FORWARD,
                                         ResultSet.CONCUR_READ_ONLY);

1つ目の引数はカーソルのタイプを指定します。ここで指定できる引数の値は以下の3つです。

ResultSet.TYPE_FORWARD_ONLY カーソルは最初から最後まで順方向にしか移動できません。
ResultSet.TYPE_SCROLL_INSENSITIVE カーソルは順方向・逆方向いずれにも移動可能です。ただし他による変更を反映しません。
ResultSet.TYPE_SCROLL_SENSITIVE カーソルは順方向・逆方向いずれにも移動可能です。また他による変更も反映します。

この引数は、結果セットの取得の際に使用できるメソッドに影響が出ます。「ResultSet.TYPE_FORWARD_ONLY」の場合、「next()」メソッドしか使用できません。それ以外の場合には、以下のメソッドも使用可能となります。

absolute(int) 引数で指定された行番号に移動します。1行目が1、2行目が2です。負の数の場合には、最終行から逆順に数えた行に移動します。
afterLast() 最終行の1つ後ろに移動します。
beforeFirst() 先頭行の1つ前に移動します。
first() 先頭行に移動します。
last() 最終行に移動します。
previous() 1つ前の行に移動します。
relative(int) 引数で指定された数だけ、カーソルと移動します。1を指定した場合はnext()と、-1を指定した場合はprevious()と同じです。

「createStatement」の2つ目の引数は、変更可能性を指定します。

ResultSet.CONCUR_READ_ONLY カーソルはデータの読み出ししかサポートしません。
ResultSet.CONCUR_UPDATABLE カーソルは変更可能です。カーソルを用いたデータの挿入・変更・削除がサポートされます。

「ResultSet.CONCUR_UPDATABLE」を指定すると、ResultSetを用いた更新処理が可能となります。

「createStatement」で引数を指定しない場合、「ResultSet.TYPE_FORWARD_ONLY」「ResultSet.CONCUR_READ_ONLY」を指定した場合と同じになります。ちなみにPostgreSQLのJDBCドライバは「ResultSet.TYPE_INSENSITIVE」を指定した場合と同じになるので注意してください。

6.2.ResultSetを用いたupdate

ResultSetを用いたupdateについて説明します。

 conn.setAutoCommit(false);
 final String sql="select DEPTNO,DNAME,LOC from DEPT";
 PreparedStatement statement=conn.prepareStatement(sql,ResultSet.TYPE_SCROLL_INSENSITIVE,ResultSet.CONCUR_UPDATABLE);
 ResultSet result=statement.executeQuery();
 while(result.next()){
   String loc=result.getString(3);
   if(loc.equals("CHICAGO"){
     loc="SEATTLE";
     result.updateString(3,loc);
    result.updateRow();
  }
}
conn.commit();

まず「ResultSet.CONCUR_UPDATABLE」を指定して「Statement」を作成します。サンプルでは「PreparedStatement」を使用するので、「prepareStatement」の3つ目の引数に値を指定しています(3行目)。

通常と同じような方法でデータを取得しますが(5・6行目)、もし該当する行のデータを変更したい場合には「updateXXX」メソッドを使用します。サンプルでは、Stringのデータを更新するので「updateString」メソッドを使用します(9行目)。1番目の引数は更新する列番号、2番目の引数は更新後の値です。その他の「updateXXX」メソッドもこれとほぼ同じです。「updateXXX」メソッドを呼び出した後は、「updateRow」メソッドを呼び出します(10行目)。

サンプルでは最後にコミットしています。コネクションが「AutoCommit」モードである場合には、「updateXXX」メソッドが実行されるたびに、更新がデータベースに反映されます。

ResultSetを用いたupdate処理は、update文をSQLで実行するのと大差ないように思われます。しかしデータの取得を行いながらデータの更新を行いたい場合や、条件によって処理を変えたい場合(例えば1000以上は10引いて、100以下の場合は10上乗せする等)にはこの方法は有用です。

最後に1つ注意があります。ResultSetを用いた更新処理を行う場合、実行するSQL文に「*」を使用することはできません。また複数のテーブルを結合するようなSQL文も使用することができません。

(実習課題1)

以下のコンソールアプリケーションを作成しなさい。

  • まず「DEPT」テーブルの値を表示する。
  • 表示しつつ「DEPTNO」が「10」である値の「LOC」を「WASHINGTON」にし、「LOC」が「DALLAS」のものの値を「SEATTLE」に変更すること。
  • プログラム実行後、データベースの値が更新されている事を確認する事。

6.3.ResultSetを用いたinsert

次にinsertについて説明します。insertはinsert用の行があり、そこに移動して処理を行います。サンプルでは前半部を省略しています。

 ResultSet result=statement.executeQuery();
 result.moveToInsertRow();
 result.updateInt(1,50);
 result.updateString(2,"FINANCE");
 result.updateString(3,"NEW YORK");
 result.insertRow();
result.moveToCurrentRow();
conn.commit();

5行目の「moveToInsertRow」がinsert用の行にカーソルを移動させるメソッドです。insert用の行に移動してからは、updateの際と同じく「updateXXX」メソッドで値を設定します(6~8行目)。最後に「insertRow」メソッドが呼び出された時点で、設定された値がDBに挿入されます(9行目)。データが確定するのは11行目のcommitされたときです。

10行目の「moveToCurrentRow」は「moveToInsertRow」を呼び出す時点でカーソルがいた行に戻るメソッドです。これにより、結果セットからの値の取り出しを引き続いて行う事ができます。このとき、挿入された行が結果セットに含まれるかどうかはJDBCドライバによります。これについては以降の節で説明します。

(実習課題2)

以下のコンソールアプリケーションを作成しなさい。

  • まず「DEPT」テーブルの値を表示する。
  • 表示後、新しいデータの挿入を行う。挿入する値は、コンソールからの入力によって指定するようにする事。
  • プログラム実行後、入力したデータがテーブルに挿入されている事を確認する事。

6.4.ResultSetを用いたdelete

最後にdeleteについて説明します。

ResultSet result=statement.executeQuery();
 while(result.next()){
   if(result.getInt(1)==20){
     result.deleteRow();
   }
 }
conn.commit();

deleteは削除したい行にあるときに、「deleteRow」メソッドを呼び出すだけです(7行目)。実際にデータベースに反映されるのは、commitを行った段階です。

(実習課題3)

以下のコンソールアプリケーションを作成しなさい。

  • まず「DEPT」テーブルの値を表示する。
  • 表示後、削除したい行の「DEPTNO」をコンソールから入力し、その行をResultSetを用いて削除する事。
  • プログラム実行後、入力したデータがテーブルから削除されている事を確認する事。

6.5.ResultSetで更新処理を行った場合の可視性

自分自身または他のResultSet(他のセッションではない)によって行われた変更が、ResultSetから見えるかどうかはJDBCドライバやデータベースに依存します。ResultSetのタイプによっても異なります。

それを調査するためのメソッドが、「java.sql.DatabaseMetadata」インタフェースで定義されています。3.3節「トランザクションの隔離レベル」でも使用したかと思います。以下がResultSetによる更新処理の可視性を調査するメソッドです。引数は全てResultSetのタイプ(「ResultSet.TYPE_FORWARD_ONLY」「ResultSet.TYPE_SCROLL_INSENSITIVE」「Resultset.TYPE_SCROLL_SENSITIVE」のいずれか)で指定し、結果は全て「true」または「false」で返されます。「true」の場合はサポートしている事を意味します。

ownInsertsAreVisible(int) 自身のResultSetによって挿入された行を参照できるか
ownUpdatesAreVisible(int) 自身のResultSetによって変更された行を参照できるか
ownDeletesAreVisible(int) 自身のResultSetによって削除された行が判別できるか
othersInsertsAreVisible(int) 他のResultSetによって挿入された行を参照できるか
othersUpdatesAreVisible(int) 他のResultSetによって変更された行を参照できるか
othersDeletesAreVisible(int) 他のResultSetによって削除された行が判別できるか
insertsAreDetected(int) ResultSetの「rowInserted」メソッドで、対象行が挿入されたものである事を検出できるか
updatesAreDetected(int)

ResultSetの「rowUpdated」メソッドで、対象行に変更があったことを検出できるか

deletesAreDetected(int)

ResultSetの「rowDeleted」メソッドで、対象行が削除された事を検出できるか

(実習課題4)

Oracle ThinドライバおよびOracle OCIドライバの可視性を調べなさい。

↑このページの先頭へ

こちらもチェック!

PR
  • XMLDB.jp