通常、SQL命令の実行に際しては、「SQL命令の解析→コンパイル→実行」というステップを踏む必要があります。これは、同一の命令が繰り返し実行される場合にも同様であり、大きなボトルネックの要因ともなります。
そこで登場するのがPreparedStatementインターフェイスです。PreparedStatementインターフェイスはStatementインターフェイスを継承する「準備済みステートメント」を表現します。「準備済みステートメント」とは、その名のとおり、SQL命令の解析・コンパイルをあらかじめすませた状態で保持することで、SQL命令を繰り返し実行する場合には直接に実行処理に入れるという代物です。その性質上、1度目の実行時には、Statementインターフェイス同様、「解析→コンパイル」の過程を踏まなければならないため、単発的な命令の実行にはあまり意味がありませんが、パラメータのみが異なる同一の命令を繰り返し実行したいという場合、パフォーマンスを改善することができます。
また、セキュリティという意味からもPreparedStatementインターフェイスは有効です。というのも、PreparedStatementインターフェイスは実行時に渡されたパラメータをエスケープ処理します。つまり、もしも入力データにオリジナルのSQL命令を改ざんするような予約文字が混在していたとしても、PreparedStatementインターフェイスは内部的にこれを処理してくれるというわけです。昨今、問題視されるSQLインジェクションなどのセキュリティ対策という意味でも、積極的にPreparedStatementインターフェイスを使用することをお勧めします。
さて、以下ではそのPreparedStatementインターフェイスを利用して、アクセスログをデータベースに記録するサンプルを作成してみることにしましょう。
<%@ page contentType="text/html; charset=Shift_JIS" import="java.sql.*,java.util.*,java.text.*" %> <% Class.forName("org.gjt.mm.mysql.Driver"); Connection db=DriverManager.getConnection("jdbc:mysql://localhost/sample?user= root&password= root&useUnicode=true&characterEncoding=Shift_JIS"); PreparedStatement objSql=db.prepareStatement("INSERT INTO log_rec(url,atime,usr,referer) VALUES(?,?,?,?)"); SimpleDateFormat objFmt=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); objSql.setString(1,request.getServletPath()); objSql.setString(2,objFmt.format(Calendar.getInstance().getTime())); objSql.setString(3,request.getHeader("user-agent")); objSql.setString(4,request.getHeader("referer")); objSql.executeUpdate(); objSql.close(); db.close(); %>
大まかなデータベースアクセスの流れは、前項のStatementインターフェイスの場合と同様です。ただ、PreparedStatementオブジェクトを生成するには、Connection#createStatementメソッドではなく、prepareStatementメソッドを使用する点に注意してください。
前述したように、PreparedStatementインターフェイスはあらかじめコンパイル処理されたSQL命令です。従って、オブジェクト生成時にSQL命令を指定する必要がありますが、このSQL命令に含まれている「?」という文字に注目してみてください。
これは動的にパラメータをセットできる箇所を表わす「プレイスホルダ」と呼ばれるものです。PreparedStatementインターフェイスではこのようにあらかじめプレイスホルダを設定しておくことで、あとから動的にパラメータを渡すことができるのです。
パラメータを設定するのはsetXxxxxメソッドの役割です。セットするデータの型に応じて、setArray、setAsciiStream、setBigDecimal、setBinaryStream、setBlob、setBoolean、setByte、setBytes、setCharacterStream、setClob、setDate、setDouble、setFloat、setInt、setLong、setNull、setObject、setRef、setShort、setString、setTime、setTimestamp、setURLなどを利用することが可能です。冒頭ご紹介したように、setXxxxxメソッドではパラメータ設定時に予約文字のエスケープ処理が行われますので、個別に文字列処理を施す必要はありません(逆に文字列処理を行ってしまった場合、二重にエスケープが行われてしまうので注意してください)。
パラメータをすべて設定した後、PreparedStatement#executeUpdateメソッドでSQL命令を実行します。
PreparedStatementインターフェイスは「準備済みSQL命令」を表現します。PreparedStatementインターフェイスを利用することで、同一のSQL命令の繰り返し実行を効率化できるだけでなく、SQLインジェクションのようなセキュリティホールを未然に防ぐことが可能です。
Copyright © ITmedia, Inc. All Rights Reserved.