RowSetは、JDBCで伝統的に使われているResultSetインターフェースを拡張したものです。
JavaBeans的なプロパティを持ち、
結果集合の他に、データベース接続情報やSQL文も内部に持つことができます。
つまり(Statement+ResultSet)のようなものです。
RowSetは最も基本的なインターフェースで、
それを発展させたサブインターフェースが性質によって幾つか提供されていますが、
最も特徴的な性質を持つのはCachedRowSetというインターフェースです。
これは、ResultSetや他のRowSetのサブインターフェースと異なり、
「DB接続を保持しておく必要がない」という特徴を持ちます。
ResultSetに格納した結果集合は、DB接続を終了すると失われてしまいます。
そのため、たくさんのクライアントからDBアクセスがある一般のWebアプリケーションでは、
一旦ResultSetから別のオブジェクト(通常2次元の配列やリスト)にコピーする手間が発生します。
RowSetはDB接続を終了してもデータがそのまま参照でき、
実際にJSF(Java Server Faces)では、
RowSetに格納したデータをJavaコーディング不要でHTMLのTABLE形式で出力するカスタムタグを提供しています。
これらRowSetの実装クラスは、新しいJ2SE 5.0(Tiger)には標準で同梱されていますが、
まだ広く使われているJ2SE 1.4.xでも、別途RowSetの標準実装を入手すれば、使うことができます。
それはhttp://java.sun.com/products/jdbc/
のRowSet Reference Implementationから無償でダウンロードできます。
現在のバージョンは1.0.1です。また、
こちら
の1.0 Early Accessも使えます。
ダウンロードしたアーカイブを展開すると、rowset.jarというファイルがあるので、
これをCLASSPATHに追加します。
package test.jdbc.rowset;
import java.sql.Connection;
import javax.sql.rowset.CachedRowSet;
import com.sun.rowset.CachedRowSetImpl;
public class CachedRowSetExample1 {
public static void main(String[] args) throws Exception {
Class.forName("com.mysql.jdbc.Driver");
CachedRowSet crset = new CachedRowSetImpl();
crset.setCommand("SELECT * FROM SHITEN ORDER BY SHITEN_CODE");
crset.setUrl("jdbc:mysql://localhost/udb" +
"?useUnicode=true&characterEncoding=SJIS");
crset.setUsername("urano");
crset.setPassword("momomo");
crset.setTransactionIsolation(Connection.TRANSACTION_READ_COMMITTED);
crset.execute();
while(crset.next()){
System.out.println(crset.getString(1) + "\t" +
crset.getString(2) + "\t" + crset.getInt(5));
}
}
}
|
1つのテーブルの全件を取得し、順番に表示するだけの簡単なサンプルです。
DB接続はCachedRowSetが内部的に行います。
が、従来のJDBCのAPI(Connectionを作り、Statementを作り、問合せを発行する)
を使った後、CachedRowSet#populate()というメソッドで、
取得したResultSetオブジェクトからデータをRowSetオブジェクトに転写することも可能です。
package test.jdbc.rowset;
import java.sql.Connection;
import javax.sql.rowset.CachedRowSet;
import com.sun.rowset.CachedRowSetImpl;
public class CachedRowSetExample2 {
public static void main(String[] args) throws Exception {
Class.forName("com.mysql.jdbc.Driver");
CachedRowSet crset = new CachedRowSetImpl();
crset.setCommand("SELECT * FROM SHITEN ORDER BY SHITEN_CODE");
crset.setUrl("jdbc:mysql://localhost/udb" +
"?useUnicode=true&characterEncoding=SJIS");
crset.setUsername("urano");
crset.setPassword("momomo");
crset.setTransactionIsolation(Connection.TRANSACTION_READ_COMMITTED);
crset.execute();
while(crset.next()){
String shitenName = crset.getString(2);
if(shitenName.equals("上野")){
crset.updateInt(5, 450);
crset.updateRow();
System.out.println("更新しました。");
}
}
crset.acceptChanges();
System.out.println("処理完了");
}
}
|
今度はRowSet上のデータを更新することで、DBにもその変更を反映させるサンプルです。
更新対象の行はこの例のようにnext()で一行ずつ探すこともできますが、
absolute()メソッドで直接対象行に移動することでも可能です。
それでupdate???()メソッドで各カラムの値を更新し、
updateRow()で行の更新を確定し、
最後にacceptChanges()でDBに更新を反映(&コミット)します。
●RIのバグ?
データベースがMySQLで、
現在のSunのRIで、CacheRowSetImplにプレースホルダー(?)を使うと、
次のようなエラーになり、使えないようです。
java.sql.SQLException: Can not issue executeUpdate() for SELECTs
at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:1746)
at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:1597)
at com.sun.rowset.internal.CachedRowSetReader.readData(CachedRowSetReader.java:146)
at com.sun.rowset.CachedRowSetImpl.execute(CachedRowSetImpl.java:583)
at com.sun.rowset.CachedRowSetImpl.execute(CachedRowSetImpl.java:1165)
|
参考URL:http://lists.mysql.com/java/6496
(first uploaded 2004/11/11 last updated 2004/12/22, URANO398)
|