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から)に注意