PreparedStatement
3.2 PreparedStatement
今までのプログラムでは、Statementを利用しSQL文を実行していました。JDBCには、効率よくSQLを実行するためにStatementを拡張したPreparedStatementが存在します。本節では、PreparedStatementについて学習していきます。
3.2.1 PreparedStatementとは
PreparedStatementは、前節で学習したStatementと同じSQL文をデータベースへ送信するための準備を行う機能の1つです。実行するSQL文を先に解析しておくことで、処理速度の向上を図ります。
StatementとPreparedStatementの違いは以下に示す通りになります。
・ Statement
① SQL文を受け取って解析し、すぐに実行します。
・ PreparedStatement
① SQL文を受け取って解析し、値があればいつでも実行できる状態にします。
② SQL文に必要な値をセットします。
③ SQL文を実行します。
上記の手順を比べると、手順が増えたPreparedStatementの方が、手間がかかって遅くなる印象を受けると思います。PreparedStatementの最大の特徴はSQL文の解析と実行の処理を別々に行う点で、これによって処理速度を向上させることができます。1回のSQLを実行する場合には、処理速度はほとんど変わることはありませんが、検索条件や更新する値のみが異なるSQL文を大量に実行する場合、実行する度にSQL文の解析を行うStatementと、初めの1回しかSQL文の解析を行わないPreparedStatementとでは処理速度に大きな違いが出てきます。
3.2.2 PreparedStatementを利用したデータベースアクセスの基本構文
PreparedStatementを利用した処理の流れは次のようになります。
① JDBC(java.sqlパッケージ)をインポートする。
② JDBCドライバを読み込む。
③ データベースへ接続する。
④ 基準となるSQL文を作成する。
String sql = “UPDATE bookinfo SET price= ? WHERE isbn= ?";
⑤ SQL文をデータベースに送るための準備を行う。
PreparedStatement ps = con.prepareStatement(sql);
⑥ パラメータ変数に値をセットする。
ps.setInt(パラメータのインデックス, パラメータ値);
ps.setString(パラメータのインデックス, パラメータ値);
⑦ SQL文をデータベースへ送信し、結果を受け取る。
int rowsCount = ps.executeUpdate(); //更新系
ResultSet rs = ps.executeQuery(); //検索系
PreparedStatementを利用する場合、基準となるSQL文を作成します。SQL文は、動的に変化する値の部分に「?」(はてなマーク)を使用します。この「?」(はてなマーク)のことをパラメータ変数やプレースホルダーと呼びます。また、⑤の処理ではSQLをデータベースに送る準備を行う際に、createStatement()メソッドの代わりにprepareStatement()メソッドを利用します。この時、引数に渡されたSQL文を解析をします。⑥の処理では、SQL文のパラメータ変数に値をセットしています。int型の値をセットする場合には「setInt()メソッド」、String型の文字列をセットする場合には「setString()メソッド」を利用します。⑦の処理で、SQL文をデータベースへ送信し実行します。⑤の時点でSQL文を渡されているので、executeUpdate()メソッドの引数にSQL文を渡す必要はありません。
では、実際にPreparedStatementを利用したプログラムを作成してみましょう。
PreparedStatementを利用したプログラム
このプログラムは、PreparedStatement を利用してデータの更新を行うプログラムです。
① ソース・フォルダー :myjdbc_kanda/src
② パッケージ :jp.co.f1.jdbc.ch03
③ 名前 :SamplePrepared
④ 作成するメソッド・スタブの選択:public static void main(String[] args) にチェックを入れる
➢ SamplePrepared.java
1 | package jp.co.f1.jdbc.ch03; |
5 | public class SamplePrepared { |
7 | private static String RDB_DRIVE="org.mariadb.jdbc.Driver"; |
8 | private static String URL="jdbc:mariadb://localhost/mybookdb"; |
9 | private static String USER="bms"; |
10 | private static String PASSWD="bms123"; |
12 | public static void main(String[] args) { |
16 | Connection con = null; |
17 | PreparedStatement ps = null; |
20 | Class.forName(RDB_DRIVE); |
21 | con = DriverManager.getConnection(URL,USER,PASSWD); |
23 | sql = "UPDATE bookinfo SET price=? WHERE isbn=?"; |
25 | System.out.println("■更新前の書籍一覧を表示"); |
28 | ps = con.prepareStatement(sql); |
30 | ps.setString(2,"00001"); |
31 | num = ps.executeUpdate(); |
32 | System.out.println("\n" + num + "件データを更新しました。\n"); |
34 | System.out.println("■更新後の書籍一覧を表示"); |
37 | System.out.println("JDBCデータベース接続エラー"); |
40 | try{ps.close();}catch(SQLException ignore){} |
43 | try{con.close();}catch(SQLException ignore){} |
48 | private static void selectAll(){ |
49 | Connection con = null; |
50 | PreparedStatement ps = null; |
53 | Class.forName(RDB_DRIVE); |
54 | con = DriverManager.getConnection(URL,USER,PASSWD); |
56 | String sql = "SELECT * FROM bookinfo WHERE isbn LIKE ?"; |
58 | ps = con.prepareStatement(sql); |
59 | ps.setString(1, "000%"); |
60 | ResultSet rs = ps.executeQuery(); |
62 | System.out.println("isbn -> " + rs.getString("isbn") + |
63 | "\t title -> " + rs.getString("title") + |
64 | "\t price-> " + rs.getInt("price")); |
66 | }catch (Exception e) { |
67 | System.out.println("JDBCデータベース接続エラー"+e); |
70 | try{ps.close();}catch(SQLException ignore){} |
73 | try{con.close();}catch(SQLException ignore){} |
実行結果
解説
このプログラムの大きな構成として、12行目から46行目でデータの更新処理を記述したmain()メソッドを定義しています。更に48行目から76行目ではデータを表示するselectAll()メソッドを定義しています。この2つのメソッドではUPDATE処理とSELECT処理を行なっていますが、どちらもPreparedStatementを利用してSQL文の実行を行なっています。
PreparedStatementを利用するために23行目でパラメータ変数を用いたSQL文を定義しています。「?」(はてなマーク)の部分が動的に変えることのできるパラメータ変数になっています。それ以外の部分は、実行する度に使い回される定型文となります。
23: sql = "UPDATE bookinfo SET price=? WHERE isbn=?";
28行目でprepareStatement()メソッドの引数にSQL文を渡しています。この時SQL文の解析が行われます。
28: ps = con.prepareStatement(sql);
29行目と30行目でSQL文の「?」(はてなマーク)で記述されていたパラメータ変数に値をセットしています。
29: ps.setInt(1, 3000);
30: ps.setString(2,"00001");
各パラメータ変数にメソッドを利用して値をセットするため、パラメータ変数の数だけメソッドを実行します。このプログラムでははてなマークが2つあるため、メソッドを2回実行しています。
なお、値をセットするメソッドには引数が2つあり、第1引数にはパラメータのインデックス、第2引数にはパラメータ変数にセットする値を記述します。そのため、「ps.setInt(1, 3000);」は「1個目のはてなマークに3000をセットする。」という処理になり、「ps.setString(2, “00001”);」は「2個目のはてなマークに”00001″をセットする。」という処理になります。
このSQL文を作成する手順は以下のようになります。
SQL文の中に記述された「?」に対して、先頭から順番に1、2、3・・・と番号が割り当てられます。このプログラムではpriceの値が1番、isbnの値が2番になります。
図 3.1.3初期データとSQL実行後のデータ
次に、セットメソッドの第一引数の値に対応する「?」に第二引数の値をセットします。
図 3.2.2 パラメータ変数への値の設定
その結果、以下のSQL文が生成され、実行されます。
UPDATE bookinfo SET price = 3000 WHERE isbn='00001';
実行結果を確認すると、isbnが00001のデータのpriceが変更されているのが確認できます。
更にselectAll()メソッド内でも同様の処理が行われています。
56行目で基準となるパラメータ変数を用いたSQL文定義しています。
56: String sql = "SELECT * FROM bookinfo WHERE isbn LIKE ?";
59行目でSQLのパラメータ変数に値をセットしています。
59: ps.setString(1, "000%");
この処理でSQL文のLIKEの後ろのはてなマークに値がセットされるため、次のようなSQL文になります。
SELECT * FROM bookinfo WHERE isbn LIKE '000%';
ポイント
- PreparedStatementを利用するとSQL文を予め解析しておき、使いまわすことができるため処理速度の向上を図ることができる。
- PreparedStatementを利用する場合のSQL文は値の部分をパラメータ変数と呼ばれる「?」(はてなマーク)で記述する。
- パラメータ変数に値をセットする場合、セットメソッドの引数にパラメータ変数のインデックスと値を記述する。
StatementとPreparedStatementの処理のタイミング
以下の図はStatementとPreparedStatementを利用した処理の流れをまとめた図です。
簡単に目を通しておきましょう。

NEXT>> 3.3 本章のまとめ