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

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

【React】チュートリアル その1

2回目のReactの勉強会に参加してきました。今回はもくもく会だったのですが、そこでReactの公式チュートリアルを進めてきました。
チュートリアルでは「三目並べ」を作っていきます。

今回は「チュートリアルの準備 」から「ゲーム勝者の判定 」まで進めたので自分の振り返り用にまとめます。

ja.reactjs.org

※今回のアプリで使用しているCSSは、チュートリアルで用意されているものを使用しています。CSSについての解説はしていません。

【目次】

1. 盤面のClass Component

盤面クラスコンポーネントのソースは次の通り。

class Board extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      squares: Array(9).fill(null),
      xIsNext: true,
    };
  }

  /**
   * マス目のクリックイベント.
   * @param {*} i マス目のインデックス番号
   */
  handleClick(i) {
    const squares = this.state.squares.slice();
    if (calculateWinner(squares) || squares[i]) {
      return;
    }
    squares[i] = this.state.xIsNext ? 'X' : 'O';
    this.setState({
      squares: squares,
      xIsNext: !this.state.xIsNext,
    });
  }

  /**
   * マス目描画.
   * @param {*} i マス目のインデックス番号
   */
  renderSquare(i) {
    return (
      <Square
        value={this.state.squares[i]}
        onClick={() => this.handleClick(i)}
      />
    );
  }

  render() {
    const winner = calculateWinner(this.state.squares);
    let status;
    if (winner) {
      status = 'Winner:' + winner;
    } else {
      status = 'Next player:' + (this.state.xIsNext ? 'X' : 'O');
    }

    return (
      <div>
        <div className="status">{status}</div>
        <div className="board-row">
          {this.renderSquare(0)}
          {this.renderSquare(1)}
          {this.renderSquare(2)}
        </div>
        <div className="board-row">
          {this.renderSquare(3)}
          {this.renderSquare(4)}
          {this.renderSquare(5)}
        </div>
        <div className="board-row">
          {this.renderSquare(6)}
          {this.renderSquare(7)}
          {this.renderSquare(8)}
        </div>
      </div>
    );
  }
}

1.1. コンストラク

  constructor(props) {
    super(props);
    this.state = {
      squares: Array(9).fill(null),
      xIsNext: true,
    };
  }

コンストラクタでは、stateとして

  • squares : 3 x 3 の盤面の状態を保持する
  • xIsNext : プレーヤーの手番を管理。盤面では"X"と"O"を交互に指していく。

という2つの状態を宣言&初期化。

1.2. マス目のクリックイベント【handleClick(i)】

handleClick(i)

盤面のマス目がクリックされたときに呼び出されるメソッド。
引数はクリックされたマス目の、盤面上のインデックス番号。

const squares = this.state.squares.slice();
if (calculateWinner(squares) || squares[i]) {
    return;

calculateWinner関数に盤面の状態を渡して決着がついているかを判定。決着がすでについている、もしくはクリックされたマス目がすでに埋まっている場合は何もせずにreturnしている。

squares[i] = this.state.xIsNext ? 'X' : 'O';
this.setState({
    squares: squares,
    xIsNext: !this.state.xIsNext,
});

this.state.xIsNext ? 'X' : 'O'」で現在のプレーヤーの手番によってマス目に表示させる記号を判定している。その記号を、squares配列のクリックされたインデックス番号へ代入している。
最後に、this.setState()でstateの状態を更新している。

1.3. マス目描画メソッド【renderSquare(i) 】

 renderSquare(i) 

マス目を描画するメソッド。

return (
    <Square
    value={this.state.squares[i]}
    onClick={() => this.handleClick(i)}
    />
);

Square関数コンポーネント
・マス目の状態「this.state.squares[i]」("X" or "O" or null)をvalueという名称で、
・マス目がクリックされたときに呼び出すメソッド「handleClick」をonClickという名称で
引数として渡している。
描画を実際にするのはSquare関数コンポーネント(2. で説明)。

1.4. render()メソッド

const winner = calculateWinner(this.state.squares);
let status;
if (winner) {
    status = 'Winner:' + winner;
} else {
    status = 'Next player:' + (this.state.xIsNext ? 'X' : 'O');
}

calculateWinner関数にstateのsquaresを引数として渡して、勝負がついているかを判定。
勝負がついているかによって、描画する文字列(status)を変えている。

    return (
      <div>
        <div className="status">{status}</div>
        <div className="board-row">
          {this.renderSquare(0)}
          {this.renderSquare(1)}
          {this.renderSquare(2)}
        </div>
        <div className="board-row">
          {this.renderSquare(3)}
          {this.renderSquare(4)}
          {this.renderSquare(5)}
        </div>
        <div className="board-row">
          {this.renderSquare(6)}
          {this.renderSquare(7)}
          {this.renderSquare(8)}
        </div>
      </div>
    );
  }

上記で作成した文字列statusの描画と、盤面の各マス目をrenderSquareメソッドで描画をしている。

2. マス目の関数コンポーネント

マス目の関数コンポーネントのコードは次の通り。
関数コンポーネントは、renderメソッドのみを有して自分のstateを持たないコンポーネントのこと。

function Square(props) {
  return (
    <button className="square" onClick={props.onClick}>
      {props.value}
    </button>
  );
}

盤面のマス目をボタンとして描画している。
マス目(ボタン)が押されたとき、引数のpropsが持っている盤面クラスコンポーネントrenderSquareメソッドが呼び出される。
(1.2. マス目描画メソッド【renderSquare(i) 】を参照)

{props.value}で、マス目に"X"を描画 もしくは "O"を描画 もしくは描画しない(null)をしている。

3. 勝負判定用のヘルパー関数

function calculateWinner(squares) {
  const lines = [
    [0, 1, 2],
    [3, 4, 5],
    [6, 7, 8],
    [0, 3, 6],
    [1, 4, 7],
    [2, 5, 8],
    [0, 4, 8],
    [2, 4, 6],
  ];

  for (let i =0; i < lines.length; i++) {
    const [a, b, c] = lines[i];
    if (squares[a] && 
        squares[a] === squares[b] && 
        squares[a] === squares[c]) {
      return squares[a];
    }
  }
}

勝負がついたかを判定するためのヘルパー関数。
linesで勝負がついた時のパターンを定義している。
(横一列が3パターン、縦一列が3パターン、斜めが2パターンの計8パターン)

linesの各パターンごとに、引数のsquares(盤面の状態)を判定。「a」「b」「c」がすべて"X" もしくは すべて"O"のときに勝負がついたと判定している。

4. まとめ

Reactのチュートリアルについて、書いたコードの解説をしました。
自分の備忘録的なものなので、わかりにくいかもしれません。
次は「タイムトラベル機能の追加 」をチュートリアルで進めたら、そのコード解説を書こうと思います。

おサイフケータイで「タッチレス」の実証実験が始まるらしいよ

おサイフケータイタッチレスの実証実験が12/10(火)からはじまるらしいです。

www.nikkei.com

おサイフケータイのタッチレス化も、NTTドコモソニーソニーイメージングプロダクツ&ソリューションズ)の開発ということで、十数年前FeliCa(TM)を普及させたタッグです。

最近は〇〇Pay系のキャッシュレス決算が増えてますが、いちいちバーコードをスマホの画面に表示させるのが面倒くさいんですよね。
なので、自分は普段はおサイフケータイiDを使っています。

レジ備え付けの読み取り機に、スマホタッチするだけ。簡単(´▽`)
(キャッシュバックが多きときは〇〇Pay使ったりますよ。)

そして、とうとうタッチすら必要なくなるとな(。-`ω-)

おサイフケータイの登場で財布を出すことがなくなり、タッチレス化されることでスマホすら出さなくてよくなる。
・・・数十年後、人間の体にICチップが埋め込まれてスマホすら必要なくなるんですね
( ゚Д゚)

おサイフケータイのタッチレスの仕組み

決済そのもののシステムはFeliCaを使うらしい。
FeliCaに加えて、無線通信技術(UWB(超広帯域無線)*1Bluetoothなど)を組み合わせてタッチレスを可能にするとのこと。

一番難しいのはスマホの位置測定だろうな。

レジの位置とスマホの位置関係から決済する対象のスマホを割り出すだろうから、数センチ単位の位置測定精度がないと、
「レジに並んでいた後ろの人のスマホで決済されてしまったぁ」
とかふつうに起こりそうだし。

と思ったけど、UWBで数10㎝の程度の精度で位置測定できる屋内測定システムがあるらしい。

www.nict.go.jp


これは、サービスが実現するのも夢ではない気がするぞ( ̄д ̄)

まとめ

おサイフケータイの「タッチレス」化のニュースについてでした。
実証実験がこれから始まるのでサービスの本番稼働はまだまだ先でしょうが、「おサイフケータイのタッチレス化」今から楽しみです。

*1:近距離での高速通信が得意な無線通信方法。位置検出も可能。

AWSが量子コンピューティングサービス「Amazon Braket」を発表したらしいよ

今回はいつもと違って話題になっているIT技術やサービスなどを紹介してみます。

今日はAmazon Web Services(以降、AWS)が発表した、クラウド量子コンピューターを利用できるサービス
 Amazon Braket
です。

japan.zdnet.com

Amazon Braketは、AWS量子コンピューター導入したわけでなく、D-Wave、IonQ、Rigettiなどの量子コンピューティング企業が提供するハードウェアでいろいろ試すことができるらしいです。

それぞれの量子コンピューティング企業は下記のような感じらしい。
D-Waveの量子コンピュータは日本の企業や大学でも使われてるらしい。

【D-Wave】

D-Wave社について — D-Wave Japan

【IonQ】

IonQ、1原子を1量子ビットとする“イオントラップ”型量子コンピュータ ~既存の全量子コンピュータを上回る性能を実現 - PC Watch

【Rigetti】

量子コンピューティングでテック大手に対抗する極小企業、Rigettiの挑戦|WIRED.jp

AWS量子コンピューター分野に手を広げてきて、これから量子コンピューター界隈がにぎやかになりそうだなぁ...( = =) トオイメ目
現在はプレビュー版で利用できるらしいので、量子アルゴリズムに詳しい方は試してみてはいかがでしょうか。


ここからは、量子コンピューターについて少し書いてみようと思います。

量子コンピューターを使うメリット

量子コンピューターを使うと何がいいかというと、現在のコンピューターに比べて計算速度が桁違いに早くなること。量子コンピューターなら「組み合わせ最適化問題」とか一瞬で解けるようになる。

annealing-cloud.com

よく量子コンピューターを使った時のメリットの例に挙げられるのは、「新薬の開発スピードの向上」や「AI(人口知能)の発展」、「ビッグデータの解析に貢献」とかですかね。

量子コンピューターによるデメリット

逆に計算速度が向上することによって現れる問題としては、現在使われている暗号が容易に解読できるようになってしまうということが挙げられます。
量子コンピューターが実用化されると、「RSA」や「楕円曲線暗号」のような公開鍵暗号は役に立たなくなります。
ってことは、量子コンピューターの前ではすべての暗号文は、平文と同義なのだ!
(合ってるか??)
量子コンピューターが本格的に実用化される前に、新しい暗号化技術やセキュリティ技術がの確立が必要だと思います。本当に。。。

まとめ

これからも時々、話題になっているIT技術やサービスなどを紹介していこうと思います。

文字コード ~ 文字集合 と 符号化方式 ~

今回は文字コードについて。文字集合と符号化方式に掘り下げて勉強してみました。

1. 文字コードとは

文字コードはコンピューター上で文字を扱うために、文字にや記号に割り当てられてた数値のこと。
この文字コードは「文字集合」と「符号化方式」というもので構成されている。

1.1. 文字集合

コンピューターではどのような文字を使うのか決めておく必要がある。この扱いたい文字をまとめた集合を文字集合と呼ぶ。
ASCIIやJIS、UNICODE文字集合です。

コンピューターで文字を表すために、文字集合の文字一つ一つにユニークな番号がふってあります。このユニークな番号のことを、コードポイントと呼ぶ。

1.2. 符号化方式

文字集合をデジタルデータとして表現するために、どうやって符号化するかを決めているのが符号化方式
符号化することによって、文字集合のコードポイント*1を実際にコンピューターが理解できるデータ列(バイト列)に変換されます。
Shift-JISやUTF-8UTF-16などが符号化方式です。

2. 文字集合と符号化方式

文字集合と符号化方式の関係をUNICODEUTF-8UTF-16で説明してみます。

UNICODE
 アルファベットや記号、数字、漢字、ひらがな、アラビア文字ラテン文字など世界中の文字を集めた文字集合

UTF-8, UTF-16
 UNICODEで定義されている文字をコンピューターが理解できるバイト列に符号化するための符号化方式。

ひらがなの「あ」を、UNICODEUTF-8UTF-16で表現すると下記のようになります。

符号化方式 文字 UNICODE
コードポイント
符号化
UTF-8 U+3042 0xE3 0x81 0x82
UTF-16 0x30 0x42

UTF-8UTF-16UNICODEという文字集合の符号化方式であるため、文字「あ」のコードポイントは同じです。
異なるのは、コンピューターが理解できるように符号化したあとのバイト列です。 UTF-8は「0xE3 0x81 0x82」の3byteのバイト列に対し、UTF-16は「0x30 0x42」の2byteのバイト列となっています。

3. ASCII

ASCII(アスキーコード)は、「文字集合のコードポイント」と、「符号化したあとのバイト列(コンピューターが理解できるバイト列)」が同じであるため、符号化方式を意識する必要がないとのこと。*2

4. まとめ

文字コードを掘り下げて、文字集合と符号化方式についてまとめてみました。
文字コードの世界はまだまだ奥深いけど今日はここまで。

参考

文字集合 :
https://ja.wikipedia.org/wiki/%E6%96%87%E5%AD%97%E9%9B%86%E5%90%88
文字符号化方式 :
https://ja.wikipedia.org/wiki/%E6%96%87%E5%AD%97%E7%AC%A6%E5%8F%B7%E5%8C%96%E6%96%B9%E5%BC%8F
文字コードUTF-8とは〜世界で最もポピュラーな文字コードとその仕組みを学ぼう :
https://ferret-plus.com/7006

*1:コードポイントは文字集合の文字に頭から順番に割り振った番号であり、符号化方式ではないので注意。

*2:https://ja.wikipedia.org/wiki/ASCII

DockerでReactの開発環境を作成してみる

前回、Reactの開発で「CodeSandBox」というオンラインエディタを使用していました。今回はDockerでReactの開発環境を作成してみます。

1. 作業ディレクト

今回は下記のようなディレクトリ構成を準備します。

react-app
├─ docker-compose.yml
└─ docker
      └─ Dockerfile_node

2. Dockerfileの準備

Reactの開発環境にはNode.jsというサーバーサイドのJavaScript環境が必要らしいので、DockerイメージにはNode.jsの公式イメージを使用します。
今回は、「Dockerfile_node」というファイル名でDockerfileを作成します。

FROM node:13.2.0-stretch

WORKDIR /usr/src/app

作業ディレクトリとして「/usr/src/app」を指定しておきます。

3. docker-compose.ymlの作成

Docker Composeは複数のコンテナをまとめて管理するためのツールです。コンテナの構成情報は「docker-compose.yml」というファイルに定義します。
今回は、コンテナはNode.jsの1つしか管理しませんが、ホストとコンテナのディレクトリ共有や、Reactの実行コマンドをまとめて管理するために「docker-compose.yml」ファイルを使用します。

version: "3.3"
services:
  node:
    build: 
      context: ./docker
      dockerfile: Dockerfile_node
    environment:
      - NODE_ENV=development
    volumes:
      - ./:/usr/src/app
    command: sh -c "cd react-sample && yarn start"
    ports:
      - "3000:3000"

version

ファイル先頭はDocker Composeのバージョンになります。

services

今回は「node」という1つのサービスのみを定義しています。

build

Dockerfileにイメージの構成を記述して、それをベースイメージに指定するときはbuildにDockerfileの情報を記述します。
contextは、Dockerfileがあるディレクトリのパスを指定しています。
dockerfileで、DockerFileのファイル名を指定します。

environment

コンテナ内の環境変数を指定します。
NODE_ENVは、実行する環境の指定ができます。「development」は開発環境であることを明記しています。

volumes

コンテナにボリュームをマウントするときに指定します。
今回は「docker-compose.yml」ファイルが存在するディレクトリに、コンテナ内の「/usr/src/app」ディレクトリをマウントします。

command

コンテナ内で実行するコマンドを指定します。

ports

コンテナが外部に対して公開するポートを指定します。

4. Dockerイメージのビルド

「docker-compose.yml」ファイルが配置されているディレクトリで、Dokcerイメージをビルドします。

docker-compose build

ビルドコマンドの実行結果は下記です。

Building node
Step 1/2 : FROM node:13.2.0-stretch
13.2.0-stretch: Pulling from library/node
844c33c7e6ea: Pull complete                                                                                             ada5d61ae65d: Pull complete                                                                                             f8427fdf4292: Pull complete                                                                                             f025bafc4ab8: Pull complete                                                                                             7a9577c07934: Pull complete                                                                                             9b4289f800f5: Pull complete                                                                                             e5b5cb6034b3: Pull complete                                                                                             77980c72a787: Pull complete                                                                                             7c5d27382edd: Pull complete                                                                                             Digest: sha256:ead25ba89fdbace5701281b1f8c35c317ed09d10ba30fcd01ded881406b84e7f
Status: Downloaded newer image for node:13.2.0-stretch
 ---> 760e12e87878
Step 2/2 : WORKDIR /usr/src/app
 ---> Running in 38caf6505065
Removing intermediate container 38caf6505065
 ---> 51727fdae0a7

Successfully built 51727fdae0a7
Successfully tagged react-app_node:latest

Dockerイメージのダウンロードと作業ディレクトリの指定が実行されます。

5. Create React App

Reactの開発環境のセットアップには「Create React App 」というものを使用するのが良いらしいです。

ja.reactjs.org

なので、以下のコマンドでCreate React Appのインストールと、開発用プロジェクトの作成を行います。

docker-compose run --rm node sh -c "npm install -g create-react-app && create-react-app react-sample"

コマンドを実行すると、インストールとプロジェクトの作成に数分かかります。
完了すると、「react-sample」というプロジェクトが作成されていることが確認できました。

f:id:masakiXX0:20191128230949j:plain
「react-sample」プロジェクト

6. コンテナの起動&Reactの実行

以下のコマンドで、「docker-compose.yml」をもとに、コンテナの起動が行われます。さらに、「docker-compose.yml」ファイルのcommandに記述されているコマンドにより、Reactが実行されます。

docker-compose up

コマンドの実行結果は下記です。

Recreating react-app_node_1 ... done                                                                                    Attaching to react-app_node_1
node_1  | yarn run v1.19.1
node_1  | $ react-scripts start
node_1  | Starting the development server...
node_1  |
node_1  | Compiled successfully!
node_1  |
node_1  | You can now view react-sample in the browser.
node_1  |
node_1  |   Local:            http://localhost:3000/
node_1  |   On Your Network:  http://172.18.0.2:3000/
node_1  |
node_1  | Note that the development build is not optimized.
node_1  | To create a production build, use yarn build.
node_1  |

Reactが起動したので、ブラウザで「http://localhost:3000/」にアクセスしてみます。
すると下記のようなサンプルのビューが表示されれば成功です。

f:id:masakiXX0:20191128231527j:plain
http://localhost:3000/

7. まとめ

Reactの開発環境をDockerで構築してみました。今回は構築だけなので、次回、勉強会で作成したプログラムを今回構築した開発環境で動かしてみようと思います。

参考

WINGSプロジェクト阿佐志保 「プログラマのためのDocker教科書 第2版」 株式会社翔泳社

React の勉強会に行ってきた

Reactの勉強会に参加してきたので、勉強してきたことをまとめてみました。まだまだ理解が追い付いていないところがあるので、間違っているところまあるかもしれませんが、ご容赦ください<( *)>

1. Reactとは

FacebookOSSで公開している、WebのUI(ユーザーインターフェース)を作るためのJavaScriptライブラリです。

ReactはJavaScriptフレームワークだと(勝手に)思ってたのですが、ライブラリだそうです。へ~、一つ賢くなった(o゚v゚)ノ
ライブラリだから、基本的にインポートするだけで使えるって。

2.Reactの特徴

Reactには大きな特徴が3つあります。

Just The UI

ReactはMVCモデルでいうところのViewを担うライブラリだよってこと。 つまり、アプリ全体をビジネスロジックと画面表示で分けたうちの、画面表示のほう。

Virtual DOM

シンプルなコードでパフォーマンスもよい = 設計と速度が両立するかららしい。 下の例のように画面が更新されてHTMLが変更された時を考える。

【従来(Virtual DOMを使用しない場合)】
基本的に画面が更新されたときは毎回DOMを一から作成してブラウザに描画する。
一部分が変わるだけでも、更新がかかるたびに画面全体を再描画するため遅くなる。
下の例だとHTML全体が更新される。

【Virtual DOM】
更新前後のHTMLを比較して差分を求めて、その差がある部分だけをDOMにPUSHすることで更新する。
差分しか更新しないため描画が早い。
下の例だと p タグの中だけが更新される。

<div class="hoge">
    <p>Hello World!</p>
</div>

 ↓

<div class="hoge">
    <p>Hello React!</p>
</div>

Data Flow

Reactではデータフローが単純・簡潔らしい。
上位のコンポーネントから下位のコンポーネントへデータが流れていくだけ。逆方向にデータが流れることはないらしい。
額方向にデータが流れていたら、それは設計ミスを疑った方がいいとのこと。

3. 覚えておきたい用語

コンポーネント

クラスや関数で定義される、Reactでの部品。コンポーネントを組み合わせて画面が作られる。

props

コンポーネントにデータを渡すもの。
親のコンポーネントから、子のコンポーネントに渡される情報。

state

データ管理用の入れ物。
stateに自身のコンポーネントで使用してる情報が保持される。

4. 開発環境

今回の勉強会では「CodeSandBox」という、ブラウザ上でReactが書けるオンラインエディタを使用しました。

CodeSandBox : https://codesandbox.io

5. 勉強会で作ったアプリ

勉強会では簡単なToDoアプリを作成しました。
エディットボックスに入力された文字列が、画面下部のToDoリストに追加されていくというアプリです。
ソースはGitHubにアップロードしてあります。

github.com

コンポーネント、props、stateをそれぞれ使用しています。

6. まとめ

React勉強会で勉強してきたことをまとめてみました。React初心者ということで、まだまだ理解ができていないとこもあります。今回の勉強会を機に、これから少しずつ勉強をしていこうと思います。

【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:更新やカーソルの順方向以外の移動をできるようにする方法もあるらしいです。