JavaA2Z

KAB-studio > プログラミング > JavaA2Z > PreparedStatementとは

PreparedStatement

日本語 準備済み命令文
英語 prepared statement
ふりがな ぷりぺあーどすてーとめんと
フリガナ プリペアードステートメント

解説

プリペアードステートメントSQLを実するためのインターフェイス
J2SEに含まれるインターフェイスのひとつ。パッケージも含めたインターフェイス名はjava.sql.PreparedStatement。
 
プリペアードステートメントのように、「?」のパラメーターを持つSQLを実するためのインターフェイス
インターフェイスのため、newインスタンスを作ることはできない。代わりにConnectionインターフェイスのprepareStatement()メソッドインスタンスを作成しその参照を取得する。
 
?への値のセットは、PreparedStatementインターフェイスのsetInt()等のメソッドを使用する。
第1引数には?インデックスナンバーを指定する。ただし、インデックスナンバーは1から始まる。配列等と異なるため注意。たとえば「INSERT INTO TABLE_TEST VALUES( ?, ? )」というSQLの場合、最初のハテナのインデックスナンバーは1、後のハテナのインデックスナンバーは2となる。
第2引数にはセットする値を指定する。この時、値は単にSQLが置き換えられるわけではなく、適切な形式でセットされる。たとえば文字列をセットするsetString()メソッドの場合、「?」は「'セットする値'」と、文字列リテラルを作るための「'」(アポストロフィ)で囲んでセットされる。また、この「セットする値」に「'」が含まれていた場合には「\'」に置き換えられ「'」が無効化される。この無効化を「サニタイジング」と呼ぶ。
 
SQL文の実は、executeQuery()メソッドexecuteUpdate()メソッドう。SELECT文のように変化を伴わないSQLの場合にはexecuteQuery()メソッドを、INSERT文のように変化を伴うSQLの場合にはexecuteUpdate()メソッドを使用する。
 
使用後は必ずclose()メソッド呼び出し終了処理をう。このメソッド呼び出しは、呼び出し忘れを避けるため必ずfinally内でう。
決して、PreparedStatementインターフェイス参照変数に、close()メソッドを呼ぶ前に新しい参照をセットしてはならない。このような理由によりclose()メソッドを呼び出さないStatementインターフェイスインスタンスが残ると、メモリ等の資源が解放されず、後に致命的な問題となり異常終了する可能性もある。
 
SQLが、何らかの形で「外部から入力された値をセットする必要がある」場合には、必ずSQLは「セットする値を?パラメーター化する」ようにし、PreparedStatementインターフェイスを使用して実する。
これをわないとサニタイジングされず直接使用されてしまい、SQLインジェクションが起こされる可能性があるためである。

(KAB-studioからのおしらせです)

サンプルプログラム(とか)サンプルを別ウィンドウで表示サンプルをクリップボードへコピー(WindowsでIEの場合のみ)

// Sample.java
import java.sql.DriverManager;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

public class Sample
{
    public static void main( String[] args )
    {
        Connection conn = null;
        PreparedStatement psCreate = null;
        PreparedStatement psInsert = null;
        PreparedStatement psSelect = null;
        ResultSet rs1 = null;
        ResultSet rs2 = null;
        try
        {
            // この使用例の使用方法についてはSQLの項目を参照してください。
            
            // JDBCドライバをロードします。
            Class.forName( "org.hsqldb.jdbcDriver" );
            
            // コネクションを取得します。
            String url = "jdbc:hsqldb:mem:aname";
            String user = "sa";
            String password = "";
            conn = DriverManager.getConnection( url, user, password );

            // テーブルを作ります。
            psCreate = null;
            final String SQL_CREATE = "CREATE TABLE TABLE_TEST( NAME VARCHAR, VALUE INT );";
            psCreate = conn.prepareStatement( SQL_CREATE );
            psCreate.execute();

            // 行を追加します。
            // セットする値は直接記述せず、?にしておきます。
            // この?になっているSQLがプリペアードステートメントです。
            final String SQL_INSERT = "INSERT INTO TABLE_TEST VALUES( ?, ? );";
            // プリペアードステートメントは、Connectionインターフェイスの
            // prepareStatement()メソッドでPreparedStatementインターフェイスの
            // インスタンスを作って、これを使って操作します。
            psInsert = conn.prepareStatement( SQL_INSERT );
            forint iF1 = 0; iF1 < 3; ++iF1 )
            {
                // ?に値をセットします。
                // 列の指定は、インデックスナンバーで行います。
                // 1から始まるので注意。
                psInsert.setString( 1, "ネーム" + iF1 );
                psInsert.setInt( 2, iF1 );
                // execute()メソッドでSQLを実行して、行を追加します。
                psInsert.execute();
            }

            // 検索します。その際、WHEREで絞り込みを行います。
            // 絞り込みに使用する値はセットせず、?にしておきます。
            final String SQL_SELECT = "SELECT NAME, VALUE FROM TABLE_TEST WHERE NAME = ?;";
            // INSERTの時と同じく、?に値をセットする場合には
            // PreparedStatementインターフェイスを使用します。
            psSelect = conn.prepareStatement( SQL_SELECT );
            // ?に検索条件をセットします。
            // これもインデックスナンバーは1から始まるので注意してください。
            psSelect.setString( 1, "ネーム1" );
            // 検索します。
            rs1 = psSelect.executeQuery();
            while( rs1.next() )
            {
                String name = rs1.getString( "NAME" );
                int value = rs1.getInt( "VALUE" );
                System.out.println( name + ", " + value );
            }
            // ネーム1, 1

            // setInt()等のメソッドを使用した結果のSQLは、単なる「置き換え」ではありません。
            // たとえば、こんな感じのパラメーターをセットしてみます。
            psSelect.setString( 1, "' OR 'DUMMY' = 'DUMMY" );
            // もし単なる置き換えであれば、
            // 「SELECT NAME, VALUE FROM TABLE_TEST WHERE NAME = '' OR 'DUMMY' = 'DUMMY'」
            // というSQLが作られ、検索条件が変わります。ですが
            rs2 = psSelect.executeQuery();
            while( rs2.next() )
            {
                String name = rs2.getString( "NAME" );
                int value = rs2.getInt( "VALUE" );
                System.out.println( name + ", " + value );
            }
            // (0件です)

            // と、実際にはそうならず、'がサニタイジングされてそのまま検索条件になります。
            // この機能のおかげでSQLインジェクションを防ぐことができます。
        } 
        catch( SQLException e ) 
        {
            // SQLの実行で問題があった場合に投げられます。
            e.printStackTrace();
        }
        catch( ClassNotFoundException e ) 
        {
            // JDBCドライバが存在しなかった場合に投げられます。
            e.printStackTrace();
        }
        finally
        {
            if( rs1 != null )
            {
                try
                {
                    rs1.close();
                }
                catch( SQLException e )
                {
                    // 各close()メソッドからもSQLException例外が
                    // 投げられるので、拾っておきます。
                    e.printStackTrace();
                }
            }

            if( rs2 != null )
            {
                try
                {
                    rs2.close();
                }
                catch( SQLException e )
                {
                    // 各close()メソッドからもSQLException例外が
                    // 投げられるので、拾っておきます。
                    e.printStackTrace();
                }
            }

            if( psSelect != null )
            {
                try
                {
                    psSelect.close();
                }
                catch( SQLException e )
                {
                    // 各close()メソッドからもSQLException例外が
                    // 投げられるので、拾っておきます。
                    e.printStackTrace();
                }
            }

            if( psInsert != null )
            {
                try
                {
                    psInsert.close();
                }
                catch( SQLException e )
                {
                    // 各close()メソッドからもSQLException例外が
                    // 投げられるので、拾っておきます。
                    e.printStackTrace();
                }
            }

            if( psCreate != null )
            {
                try
                {
                    psCreate.close();
                }
                catch( SQLException e )
                {
                    // 各close()メソッドからもSQLException例外が
                    // 投げられるので、拾っておきます。
                    e.printStackTrace();
                }
            }

            if( conn != null )
            {
                try
                {
                    conn.close();
                }
                catch( SQLException e )
                {
                    // 各close()メソッドからもSQLException例外が
                    // 投げられるので、拾っておきます。
                    e.printStackTrace();
                }
            }
        }
    }
}
// Sample.java
import java.sql.DriverManager;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

public class Sample
{
    public static void main( String[] args )
    {
        Connection conn = null;
        PreparedStatement psCreate = null;
        PreparedStatement psInsert = null;
        PreparedStatement psSelect = null;
        ResultSet rs1 = null;
        ResultSet rs2 = null;
        try
        {
            // この使用例の使用方法についてはSQLの項目を参照してください。
            
            // JDBCドライバをロードします。
            Class.forName( "org.hsqldb.jdbcDriver" );
            
            // コネクションを取得します。
            String url = "jdbc:hsqldb:mem:aname";
            String user = "sa";
            String password = "";
            conn = DriverManager.getConnection( url, user, password );

            // テーブルを作ります。
            psCreate = null;
            final String SQL_CREATE = "CREATE TABLE TABLE_TEST( NAME VARCHAR, VALUE INT );";
            psCreate = conn.prepareStatement( SQL_CREATE );
            psCreate.execute();

            // 行を追加します。
            // セットする値は直接記述せず、?にしておきます。
            // この?になっているSQLがプリペアードステートメントです。
            final String SQL_INSERT = "INSERT INTO TABLE_TEST VALUES( ?, ? );";
            // プリペアードステートメントは、Connectionインターフェイスの
            // prepareStatement()メソッドでPreparedStatementインターフェイスの
            // インスタンスを作って、これを使って操作します。
            psInsert = conn.prepareStatement( SQL_INSERT );
            for( int iF1 = 0; iF1 < 3; ++iF1 )
            {
                // ?に値をセットします。
                // 列の指定は、インデックスナンバーで行います。
                // 1から始まるので注意。
                psInsert.setString( 1, "ネーム" + iF1 );
                psInsert.setInt( 2, iF1 );
                // execute()メソッドでSQLを実行して、行を追加します。
                psInsert.execute();
            }

            // 検索します。その際、WHEREで絞り込みを行います。
            // 絞り込みに使用する値はセットせず、?にしておきます。
            final String SQL_SELECT = "SELECT NAME, VALUE FROM TABLE_TEST WHERE NAME = ?;";
            // INSERTの時と同じく、?に値をセットする場合には
            // PreparedStatementインターフェイスを使用します。
            psSelect = conn.prepareStatement( SQL_SELECT );
            // ?に検索条件をセットします。
            // これもインデックスナンバーは1から始まるので注意してください。
            psSelect.setString( 1, "ネーム1" );
            // 検索します。
            rs1 = psSelect.executeQuery();
            while( rs1.next() )
            {
                String name = rs1.getString( "NAME" );
                int value = rs1.getInt( "VALUE" );
                System.out.println( name + ", " + value );
            }
            // ネーム1, 1

            // setInt()等のメソッドを使用した結果のSQLは、単なる「置き換え」ではありません。
            // たとえば、こんな感じのパラメーターをセットしてみます。
            psSelect.setString( 1, "' OR 'DUMMY' = 'DUMMY" );
            // もし単なる置き換えであれば、
            // 「SELECT NAME, VALUE FROM TABLE_TEST WHERE NAME = '' OR 'DUMMY' = 'DUMMY'」
            // というSQLが作られ、検索条件が変わります。ですが
            rs2 = psSelect.executeQuery();
            while( rs2.next() )
            {
                String name = rs2.getString( "NAME" );
                int value = rs2.getInt( "VALUE" );
                System.out.println( name + ", " + value );
            }
            // (0件です)

            // と、実際にはそうならず、'がサニタイジングされてそのまま検索条件になります。
            // この機能のおかげでSQLインジェクションを防ぐことができます。
        } 
        catch( SQLException e ) 
        {
            // SQLの実行で問題があった場合に投げられます。
            e.printStackTrace();
        }
        catch( ClassNotFoundException e ) 
        {
            // JDBCドライバが存在しなかった場合に投げられます。
            e.printStackTrace();
        }
        finally
        {
            if( rs1 != null )
            {
                try
                {
                    rs1.close();
                }
                catch( SQLException e )
                {
                    // 各close()メソッドからもSQLException例外が
                    // 投げられるので、拾っておきます。
                    e.printStackTrace();
                }
            }

            if( rs2 != null )
            {
                try
                {
                    rs2.close();
                }
                catch( SQLException e )
                {
                    // 各close()メソッドからもSQLException例外が
                    // 投げられるので、拾っておきます。
                    e.printStackTrace();
                }
            }

            if( psSelect != null )
            {
                try
                {
                    psSelect.close();
                }
                catch( SQLException e )
                {
                    // 各close()メソッドからもSQLException例外が
                    // 投げられるので、拾っておきます。
                    e.printStackTrace();
                }
            }

            if( psInsert != null )
            {
                try
                {
                    psInsert.close();
                }
                catch( SQLException e )
                {
                    // 各close()メソッドからもSQLException例外が
                    // 投げられるので、拾っておきます。
                    e.printStackTrace();
                }
            }

            if( psCreate != null )
            {
                try
                {
                    psCreate.close();
                }
                catch( SQLException e )
                {
                    // 各close()メソッドからもSQLException例外が
                    // 投げられるので、拾っておきます。
                    e.printStackTrace();
                }
            }

            if( conn != null )
            {
                try
                {
                    conn.close();
                }
                catch( SQLException e )
                {
                    // 各close()メソッドからもSQLException例外が
                    // 投げられるので、拾っておきます。
                    e.printStackTrace();
                }
            }
        }
    }
}

この単語を含むページ

「みだし」に含まれているページ

はてなブックマーク 詳細を表示 はてなブックマーク ブックマーク数
livedoorクリップ 詳細を表示 livedoorクリップ ブックマーク数
Yahoo!ブックマーク 詳細を表示 users
del.icio.us 登録する RSSに登録
サンプルを別ウィンドウで表示
サンプルをクリップボードへコピー(WindowsでIEの場合のみ)
update:2005/05/26
このページは、Javaプログラミング言語についての用語を網羅した辞書「JavaA2Z」の一ページです。
詳しくは「JavaA2Z」表紙の説明をご覧ください。