S-JIS[2023-10-07]
TsurugiのTsubakuro(Java通信ライブラリー)のSqlClientのResultSetのメモ。
TsubakuroのResultSetは、select結果を取得するクラス。
ResultSetはTransactionのexecuteQueryメソッド(のFutureResponse)から
取得する。
ResultSetから各レコード・各カラムの値を取得する。
ResultSetは使い終わったらクローズする必要がある。
import java.util.List; import java.util.concurrent.TimeUnit; import com.tsurugidb.sql.proto.SqlCommon.Column; import com.tsurugidb.tsubakuro.sql.ResultSet;
// トランザクション開始 var option = TransactionOption.newBuilder().setType(TransactionType.SHORT).build(); try (Transaction transaction = sqlClient.createTransaction(option).await(3, TimeUnit.SECONDS)) { // select実行 String sql = "select * from test"; try (ResultSet rs = transaction.executeQuery(sql).await(3, TimeUnit.SECONDS)) { List<? extends Column> columnList = rs.getMetadata().getColumns(); while (rs.nextRow()) { for (int i = 0; rs.nextColumn(); i++) { Column column = columnList.get(i); if (rs.isNull()) { System.out.printf("%s: null%n", column.getName()); } else { switch (column.getAtomType()) { case INT4: // int int int4 = rs.fetchInt4Value(); System.out.printf("%s: %d%n", column.getName(), int4); break; case INT8: // bigint long int8 = rs.fetchInt8Value(); System.out.printf("%s: %d%n", column.getName(), int8); break; case CHARACTER: // charやvarchar String string = rs.fetchCharacterValue(); System.out.printf("%s: %s%n", column.getName(), string); break; default: throw new UnsupportedOperationException(column.toString()); } } } } } // selectのみのトランザクションでも、必ずコミットする transaction.commit().await(10, TimeUnit.SECONDS); }
selectの実行結果(複数レコード)を取得するには、まず、ResultSetのnextRowメソッドを呼び出す。
trueが返るとレコードが有るので、trueである間ループする。
次に、ResultSetのnextColumnメソッドを呼び出す。
trueが返るとカラムが有るので、trueである間ループする。
これによりselect結果レコードのカラムを移動していく。
カラムの値がnullかどうかは、ResultSetのisNullメソッドで判定する。
null以外の場合、カラムの値はfetch系メソッドで取得する。(なぜgetというメソッド名でないかと言うと、一度しか取得できないから)
fetch系メソッドは、カラムのデータ型に一致しているメソッドを使用する必要がある。
カラムのデータ型やカラム名は、ResultSetのgetMetadataメソッドで取得できる。
select文でカラムに名前が付けられていない場合、カラム名はnullになる。(Tsurugiサーバー側で暗黙の名前を付けてくれない)
ResultSetから汎用的に読もうとすると、メタデータからデータ型をチェックする必要があり、全てのデータ型に対応する必要が生じてswitch文が長くなってしまうorz
(なお、Iceaxeはこういったことを行ってくれるので、Iceaxeを使う方が便利)
select結果の各カラムのデータ型が事前に分かっているのなら、メタデータからデータ型を取得する必要は無い。
// select実行 String sql = "select pk /*int primary key*/, value /*bigint*/ from test"; try (ResultSet rs = transaction.executeQuery(sql).await(3, TimeUnit.SECONDS)) { while (rs.nextRow()) { rs.nextColumn(); int pk = rs.fetchInt4Value(); rs.nextColumn(); Long value = rs.isNull() ? null : rs.fetchInt8Value(); System.out.printf("%d, %d%n", pk, value); } }
select文からプログラムを生成するツールやフレームワークなら、こういったソースコードを生成するのが良さそう。