JDBCのPreparedStatementは、同一のSQLでパラメーターを変更して何度も実行するのに適している。
import java.sql.PreparedStatement;
PreparedStatementは、ConnectionのprepareStatementメソッドで作成する。[2021-02-10]
prepareStatementメソッドには引数としてSQL文を渡す。
String sql = "select * from TEST where VALUE1=? and VALUE2=?"; try (PreparedStatement ps = conn.prepareStatement(sql)) { int i = 1; ps.setString(i++, "abc"); // VALUE1='abc' ps.setInt(i++, 123); // VALUE2=123 〜 }
SQL文の中で「?」(パラメーター)になっている箇所に、set系メソッドで具体的な値を指定する。
set系メソッドの第1引数は、「?」の位置番号。1から始まる。(「?」が複数あるときは先頭から順番に1,2,3…という連番になる)
「?」のある場所のデータ型に応じて、setInt()・setString()といったメソッドを使い分ける。
Javaのクラスはデータ型に応じて変換されるので(変換可能なクラスに限るが)、例えば日付に関してsetDate()を使ってセットすれば、SQL文上にto_date()等の関数を書く必要は無い。
PreparedStatementは使い終わったらクローズする必要がある。
try文でクローズするのが便利。
SQL文の中に「:name
」の様に書いて名前でパラメーターを指定する例を見かけることがあるが、これは標準のJDBCでは対応していないらしい。
(JPAでは仕様化されているらしいけど^^;)
PreparedStatementを使ってSELECTする例。[2021-02-10]
SELECTする場合はexecuteQueryメソッドを使用する。
String sql = "select * from TEST where KEY=?"; try (PreparedStatement ps = conn.prepareStatement(sql)) { ps.setInt(1, 999); try (ResultSet rs = ps.executeQuery()) { while (rs.next()) { System.out.printf("KEY =%d%n", rs.getInt("KEY"); System.out.printf("VALUE=%s%n", rs.getString("VALUE1"); } } }
PreparedStatementを使ってINSERTする例。
更新系のSQL(INSERT/UPDATE/DELETE)の場合はexecuteUpdateメソッドを使用する。
String sql = "insert into TEST (KEY) values(?)"; try (PreparedStatement ps = conn.prepareStatement(sql)) { ps.setInt(1, 999); int r = ps.executeUpdate(); System.out.println("更新件数:" + r); conn.commit(); }
PreparedStatement(Statement)には、複数のSQL文を一括して実行するバッチ機能がある。
同一のSQLでパラメーターを変えて何度も実行するなら、executeUpdate()を何回も呼ぶよりもexecuteBatch()を使う方が高速。
String sql = "insert into TEST " + "(KEY)" + " values(?)"; try (PreparedStatement ps = conn.prepareStatement(sql)) { for (int i = 0; i <= 9999; i++) { ps.setInt(1, i); ps.addBatch(); } ps.executeBatch(); System.out.println("更新件数:" + ps.getUpdateCount()); conn.commit(); }
自分のPC上のOracleで1万件のINSERTを試したら、executeUpdate()を1万回呼んで1回コミットする方法だと約5.
4秒、executeBatch()を使うと0.
2〜0.
4秒だった。
Java8で新しく日付時刻API(java.time)が追加になったが、PreparedStatementでは直接は使用できない。[2021-02-10]
(PreparedStatementのset系メソッドやResultSetのget系メソッドは、java.timeに対応していない)
しかしjava.sql.Date等の日付系クラスについては、java.timeクラスとの変換メソッドが実装されている。
java.sqlへの変換例 | java.timeへの変換例 | 備考 | |
---|---|---|---|
日付 | LocalDate ldate = 〜; |
java.sql.Date sdate = 〜; |
java.sql.Dateは年月日を扱う。 |
java.sql.Date sdate = new java.sql.Date(TimeUnit.DAYS.toMillis(ldate.toEpochDay())); |
|||
日時 | LocalDateTime ldt = 〜; |
java.sql.Timestamp sdt = 〜; |
java.sql.Timestampは年月日と時刻を扱う。 |
時刻 | LocalTime ltime = 〜; |
java.sql.Time stime = 〜; |
java.sql.Timeは時刻を扱う。 |