[Java] PreparedStatementで更新
- 2011-01-12 Wed 14:20:08
- JDBC
データベースの初期状態は以下のようになっています。

今回は、PreparedStatementというStatementのサブインタフェースを利用することで、データベースの更新処理をするプログラムを作成します。
データベースの更新については、createStatement()メソッドでSQLを発行するためのStatementオブジェクトを取得し、executeUpdate()メソッドでSQLの発行を行いました(参考)。
StatementインタフェースがあるのになぜPreparedStatementインタフェースを使うのかというと、PreparedStetementはSQL文をあらかじめ準備(Prepare)しておくため、処理が速くなるからです。
すなわち Statementでは、SQL文の解析および実行は、createStatement()メソッドではなく、executeQuery()メソッドを実行したときに行われます。一方、PreparedStatementを用いた場合、prepareStatement()メソッドで解析が行われ、executeQuery()メソッドで実行が行われます。
大量のSQL文を処理する場合、Statementでは、そのすべてについてexecuteQuery()メソッドで解析・実行が行われるのですが、PreparedStatementでは、SQL文の解析は前もってprepareStatement()メソッドで済ませてしまうため、executeQuery()メソッドはひたすらSQL文の実行に専念することができるため、処理が速くなるのです。
それでは、StatementとPreparedStatementの両方を使ってプログラムを書いてみて、両者を比較してみましょう。
Statementで更新するソース
Statementを使うソースのファイルは「DBUpdate2.java」とします。
package dbjava;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Statement;
public class DBUpdate2 {
public static void main(String[] args) throws Exception{
Connection con=null;
Statement smt=null;
try{
String name="'太郎'";
int money=5000;
String sql="update account set money="+money+" where name="+name;
con=DBManager.testConnection();
smt=con.createStatement();
smt.executeUpdate(sql);
System.out.println("名前が"+name+"の残高を"+money+"に更新しました。");
smt.close();
con.close();
}catch(SQLException e){
System.out.println("更新作業ができませんでした。");
}finally{
if(smt !=null){
try{
smt.close();
}catch(SQLException e){
e.printStackTrace();
}
}
if(con !=null){
try{
con.close();
}catch(SQLException e){
e.printStackTrace();
}
}
}
}
}
実行結果(コンソール)
名前が'太郎'の残高を3000に更新しました。
実行結果(HSQLDB)

PreparedStatementで更新するソース
PreparedStatementを使うソースのファイルは「DBUpdate3.java」とします。
package dbjava;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.PreparedStatement;
public class DBUpdate3 {
public static void main(String[] args) throws Exception{
Connection con=null;
PreparedStatement ps=null;
try{
String name="太郎";
int money=5000;
String sql="update account set money=? where name=?"; //(1)
con=DBManager.testConnection();
ps=con.prepareStatement(sql); //(2)
ps.setInt(1, money); //(3)
ps.setString(2, name);
ps.executeUpdate(); //(4)
System.out.println("名前が"+name+"の残高を"+money+"に更新しました。");
ps.close(); //(5)
con.close();
}catch(SQLException e){
System.out.println("更新作業ができませんでした。");
}finally{
if(ps !=null){
try{
ps.close();
}catch(SQLException e){
e.printStackTrace();
}
}
if(con !=null){
try{
con.close();
}catch(SQLException e){
e.printStackTrace();
}
}
}
}
}
実行結果(コンソール)
名前が太郎の残高を5000に更新しました。
実行結果(HSQLDB)

(1) PreparedStatementを使うときは、java.sql.PreparedStatement をインポートします。
(2) PreparedStatementで利用するSQL文には、? という記号を入れます。これはパラメータ変数と呼ばれ、?の部分に後で値を代入できるようにしたものです。
(3) Statementオブジェクトの取得にcreateStatement()メソッドを利用するのに対して、PreparedStatementオブジェクトを取得するにはprepareStatement()メソッドを利用します。createStatement()メソッドは引数がありませんが、SQL文をあらかじめ解析するためにprepareStatement()メソッドにはSQL文を引数とします。
(4) パラメータ変数に値をセットするのは、setXXX()というメソッドです。引数は2つあり、第1引数はパラメータ変数のインデックス、第2引数は値です。
インデックスとは、SQL文の中のいくつめの?に値をセットするかということです。数字は1から始まります(0ではないです)。第2引数には、XXXの部分でどんなデータ型を指定するかにより、setInt()であればint型を指定し、setString()であればString型を指定します。
(5) SQLの発行は、executeUpdate()やexecuteQuery()で行いますが、引数はありません。
(6) PreparedStatementにおいても、close()メソッドを使ってJDBCリソースを明示的に開放する必要があります。
PreparedStatementを使うことの利点は、処理が速いことのほかに、パラメータが自動的にエスケープされるということがあります。
パラメータがエスケープされるということを理解するために、
String name="太郎"; //(*)
の部分に注意してください。
「太郎」は、SQLではVARCHAR型ですから、SQL文でエラーを起こさないためには、(*)では "太郎" ではなく "'太郎'" にしなければならないはずです。このような、データ型によりクオーテーションをつけたりつけなかったりといった間違えやすい記述を自動的に処理してくれる賢い機能がPreparedStatementにはあります。
PreparedStatementの弱点としては、SQL文が場合によって動的に変化するようなときは不向きであることです。
PreparedStatementは便利ですが、不向きな場合に備えてStatementも自在に使えるようにしておきましょう。
スポンサーサイト
タグ :
Comments: