Java Gold SE11対策:Statement vs PreparedStatement 安全なSQLの書き方と違いを理解せよ

Java Gold SE11試験では、SQL文の実行方法やそれに使うインタフェースがよく問われます。
とくに Statement と PreparedStatement の違いは「知ってるかどうか」で大きな差がつく論点です。
この回では、それぞれの使い方と違い、安全性、そして試験対策まで含めて整理します。
目次
Statementとは?
Statement は最もシンプルなSQL実行手段です。
あらかじめJavaコード内でSQL文字列をすべて組み立ててから実行します。
例:
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery(“SELECT * FROM users WHERE id = 1001”);
このように、SQL文を文字列で渡して、そのまま実行する形です。
Statementの注意点:SQLインジェクションに弱い!
以下のように、文字列連結で動的なSQLを作ってしまうと…
String userInput = “1 OR 1=1”;
String sql = “SELECT * FROM users WHERE id = ” + userInput;
このSQLは実質:
SELECT * FROM users WHERE id = 1 OR 1=1
となり、全件取得される危険性があります。これが有名な「SQLインジェクション攻撃」です。
PreparedStatementとは?
PreparedStatement は プレースホルダ(?)を使ってSQLを事前に定義し、値は後で安全にセットする仕組みです。
例:
String sql = “SELECT * FROM users WHERE id = ?”;
PreparedStatement ps = conn.prepareStatement(sql);
ps.setInt(1, 1001);
ResultSet rs = ps.executeQuery();
? がプレースホルダで、後から setInt() などで値をバインドします。
PreparedStatementのメリット
メリット | 解説 |
セキュリティ | プレースホルダによりSQLインジェクションを防止できる |
パフォーマンス | SQLが事前にコンパイルされるため繰り返し実行時に高速 |
型安全なバインドが可能 | setInt(), setString() などで型を明示的に指定 |
試験でのよくあるひっかけ例
次のコードの正誤を問う問題が出ることがあります:
String sql = “SELECT * FROM users WHERE id = ?”;
Statement stmt = conn.createStatement();
stmt.executeQuery(sql); // ← PreparedStatementじゃないのでエラー
❌ プレースホルダ(?)を使うには PreparedStatementが必須
Statement では SQL文字列をそのまま使うしかない のが試験ポイントです。
プレースホルダの補足知識:1始まりの添字に注意
プレースホルダに値をセットするには、以下のように1から始まる添字を使います:
ps.setInt(1, 1001); // ← 1番目の「?」に1001をバインド
0から始めたくなりますが、JDBCでは1始まりなので注意!
まとめ:要点
- Statement はその場でSQLを文字列として実行する
- PreparedStatement はSQL文をテンプレ化し、安全に値をセットする
- SQLインジェクションを防ぐなら PreparedStatement一択
- プレースホルダ(?)使用時は PreparedStatement必須
- setXxx() 系メソッドで 型指定と順番(1から)に注意