ITエンジニア日記 ~NO SKILL, NO LIFE~

学んだ技術や、気になることをアウトプットしていきます。プログラミング, インフラ, etc...

【Java】ResultSetインターフェース

現在の業務がJava案件なのですが、SQLの実行結果からデータを取得するためにResultSetインターフェースを使用しているので、その覚え書き。

1. ResultSetインターフェースとは

SQL(主にSELECT文)の実行結果は、ResultSetインターフェースのオブジェクトに格納されます。

下記の例だと「executeQuery」でSQL文を実行し、その結果がResultSet オブジェクトとして取得できます。

Statement statment = connection.createStatement();

String sql = "SELECT A, B, C FROM HOGE_TABLE";
ResultSet rs = statment.executeQuery(query);

2. カーソル

ResultSetオブジェクトにはカーソルという、データの位置を指し示す概念があります。初期状態では最初の行の先頭を指し示している。「最初の行の先頭」は取得したレコードの1行目ではないので注意が必要。
実際には存在しないけど、レコードの0行目を指しているイメージ。

3. nextメソッド

nextメソッドにより、カーソルは次の行に移動します。

nextメソッドを実行するとResultSetオブジェクトに行が存在すれば戻り値としてtrueが、それ以上行がない場合にfalseが返ってきます。
よって、下記のコードのようにwhileを使ってループを回すことで、ResultSetオブジェクト内のデータをすべて取得できます。

while (rs.next()) {
    String dataA = rs.getString("A");
    String dataB = rs.getString("B");
    String dataC = rs.getString("C");
}

3.1. カーソルの進め方

デフォルトのResultSetオブジェクトは更新が不可能です。
また、カーソルは順方向にしか進めることができず、カーソルを戻すということができません。*1
よって、ResultSetオブジェクトでは最初の行から最後の行に向かって、1回だけ実行することができるということ。

ResultSet rs = statment.executeQuery(query);

// 1回目のループはデータの取得が可能
while (rs.next()) {
    String dataA = rs.getString("A");
}

// 2回目のループはもうデータが取得できない。
// rs.next())の戻り値は最初から false
while (rs.next()) {
    String dataB = rs.getString("B");
}

4. ResultSetオブジェクトに格納されているデータ件数の取得

現在の案件で、
「テーブルから取得したレコードの件数をログに出力したあとに、取得したレコードを使った処理をしたい」
という仕様がありました。
このとき、ResultSetが順方向に1度しか実行できないという制約がある中、対応策を考えました。

  1. whileループで回しながら件数をカウントする
    ⇒これだと処理しながらのカウントだから、事前に件数ログに出すことができない。

  2. 件数を取得するためSQLを、レコード取得SQLとは別に発行する
    ⇒事前に件数ログは出せるようになるが、余分にSQLを発行することになる。

  3. DTOクラスを作って、ResultSet内のデータをDTOオブジェクトのリストに入れてsizeメソッドで件数とる
    ⇒案件の制限上、DTOクラスは作れない(+o+)

  4. いっそのこと件数ログを処理が終わった後に出す
    ⇒さすがに仕様を無視するのはダメだろ...(´・ω・)


結局、2番の「件数を取得するためSQLを、レコード取得SQLとは別に発行する」という方法で実装することで落ち着きました。

5. まとめ

ResultSetについて自分の覚え書きとしてまとめてみました。

参考

*1:更新やカーソルの順方向以外の移動をできるようにする方法もあるらしいです。