JavaのPreparedStatementとは?SQLに値を安全に渡す考え方

最終更新日

Schoo Java入門 中級 第2回 データベース処理とオブジェクト設計

本記事は、Schooの「Java入門 中級【2026年版】」第2回「データベース処理とオブジェクト設計の基礎」を学ぶ前後に、JDBCの PreparedStatement の考え方を整理したい方向けの記事です。

PreparedStatement は、SQLの中で値が変わる部分を ? にしておき、Java側からあとで値をセットして実行するための仕組みです。

Schoo コースページ:Java入門 中級【2026年版】

PreparedStatementはSQLに値を安全に渡すために使う

検索条件や登録する値は、プログラムを実行するたびに変わることがあります。たとえば「idが1の曲を検索する」「idが11の曲を追加する」のように、SQLの一部だけが変わる場面です。

このとき、SQL文字列を毎回つなぎ合わせて作るのではなく、SQLの形を先に用意し、変わる値だけをあとから入れる書き方ができます。それが PreparedStatement です。

図解:? にあとから値を入れてSQLを実行する
1. SQLの形を先に用意する
SELECT id, title, artist FROM songs WHERE id = ?
? は「ここに値を入れる場所」という目印です。
2. Javaの値を ? にセットする
pstmt.setInt(1, id);
1番目の ? に、変数 id の値を入れます。
3. 値が入った条件でDBに問い合わせる
rs = pstmt.executeQuery();
PreparedStatementでは、実行時にSQL文字列を渡しません。
PreparedStatement は、SQLの形と値を分けて扱うための仕組みです。

? は値を入れる場所を表す

? は、あとから値を入れる場所を表します。この ? のことをプレースホルダと呼びます。

String sql = "SELECT id, title, artist FROM songs WHERE id = ?";

このSQLは、まだ具体的なidの値を持っていません。PreparedStatement を作ったあとで、Javaの変数を ? にセットします。

PreparedStatement pstmt = conn.prepareStatement(sql);
pstmt.setInt(1, id);

setInt(1, id) は、「1番目の ? に、int型の id をセットする」という意味です。

複数の?は左から1番、2番、3番と数える

? が複数ある場合は、SQL文の左から順番に番号を付けて考えます。

図解:setXxxの番号は ? の左からの順番
INSERT INTO songs (id, title, artist) VALUES ( ?, ?, ?)
1番目の ?
pstmt.setInt(1, id);
id列に入れる値
2番目の ?
pstmt.setString(2, title);
title列に入れる値
3番目の ?
pstmt.setString(3, artist);
artist列に入れる値
setInt(1, id)1 は、1番目の ? を表します。配列のように0からではなく、1から数えます。

ここで大切なのは、setIntsetString の第1引数が「何番目の ? か」を表していることです。Javaの配列とは違い、? の番号は1から数えます。

executeQueryやexecuteUpdateにはSQL文字列を渡さない

Statement では、実行するときにSQL文字列を渡していました。

ResultSet rs = stmt.executeQuery(sql);

一方、PreparedStatement では、SQLは conn.prepareStatement(sql) の時点で渡しています。そのため、実行時にはSQL文字列を渡しません。

PreparedStatement pstmt = conn.prepareStatement(sql);
pstmt.setInt(1, id);
ResultSet rs = pstmt.executeQuery();

INSERT、UPDATE、DELETEの場合も同じです。

PreparedStatement pstmt = conn.prepareStatement(sql);
pstmt.setInt(1, id);
pstmt.setString(2, title);
pstmt.setString(3, artist);

int count = pstmt.executeUpdate();

文字列連結よりPreparedStatementを使う理由

SQLにJavaの値を入れたいだけなら、文字列連結でも書けそうに見えます。しかし、SQL文と値を直接つなぐ書き方は、引用符の扱いが複雑になり、読み間違いや書き間違いが起きやすくなります。

また、利用者が入力した文字をSQLに混ぜる場合、意図しないSQLとして解釈される危険があります。これをSQLインジェクションと呼びます。

図解:SQLの形と値を分けると、読みやすく安全に扱いやすい
文字列連結で作る
“WHERE title = ‘” + title + “‘”
SQL文とJavaの値が混ざるため、引用符や記号の扱いを間違えやすくなります。
PreparedStatementで作る
WHERE title = ?
pstmt.setString(1, title);
SQLの形と値を分けて書けるため、条件の意味を追いやすくなります。
PreparedStatementは「値が変わる部分」を ? にして、あとからJavaの値をセットします。

PreparedStatement を使うと、SQLの形と値を分けて扱えます。初学者の段階では、まず「SQL本文に値を直接つなげない」「? にあとから値をセットする」と覚えると理解しやすいです。

確認問題

次のINSERT文を PreparedStatement で実行するとします。

String sql = "INSERT INTO songs (id, title, artist) VALUES (?, ?, ?)";

int id = 11;
String title = "夜明けのビート";
String artist = "スカイライン";
  1. conn.prepareStatement(sql) で作成した PreparedStatement を変数 pstmt に代入してください。
  2. 1番目、2番目、3番目の ? に、それぞれ idtitleartist をセットしてください。
  3. INSERTを実行し、登録件数を count に代入してください。

確認問題の回答例を見る

まとめ

  • PreparedStatement は、SQLの形と値を分けて扱うために使う
  • ? は、あとから値を入れる場所を表す
  • setInt(1, id)1 は、1番目の ? を表す
  • PreparedStatement では、実行時の executeQuery()executeUpdate() にSQL文字列を渡さない

関連する記事

シェアする