DELETE文でデータを削除する方法(初心者向けサンプル)Springで学ぶ基本の削除処理
新人
「Springでデータベースのデータを削除する方法ってあるんですか?」
先輩
「あるよ。DELETE文を使って、特定のデータを削除する処理を作れるんだ。SpringとJDBCを使えば簡単に実装できるよ。」
新人
「画面からボタンを押して削除するような仕組みも作れるんですか?」
先輩
「もちろん可能だよ。画面からIDを送って、Controllerを経由してRepositoryでDELETE文を実行する仕組みを作るんだ。」
新人
「それならぜひ作り方を教えてください!」
1. DELETE文とは?役割や基本構文を解説
データベースに保存された情報を削除するには、SQLのDELETE文を使用します。DELETE文は、指定した条件に一致する行をデータベースのテーブルから削除する命令です。
構文はとてもシンプルです。
DELETE FROM テーブル名 WHERE 条件;
例えば、「idが3のデータを削除する」場合、次のようになります。
DELETE FROM users WHERE id = 3;
このように、WHERE句を指定しないと、テーブルの全データが削除されてしまうため、必ず条件を指定するようにしましょう。
2. 削除処理の流れ(画面 → Controller → Repository)
SpringでDELETE文を使った削除処理を実装するには、以下のような3つのレイヤー構成で作成します。
- ① HTML画面:削除ボタンを表示し、クリックされたら対象IDをControllerに送信
- ② Controller:受け取ったIDをRepositoryに渡して削除処理を依頼
- ③ Repository:JDBCを使ってDELETE文を実行
まずはHTML画面に、削除ボタンを表示します。以下はユーザー一覧の一部で、IDを渡して削除リンクを作成している例です。
<a href="/user/delete?id=3">削除</a>
次に、Controllerでこのリクエストを受け取る処理を記述します。
@Controller
public class UserController {
@Autowired
private UserRepository userRepository;
@GetMapping("/user/delete")
public String deleteUser(@RequestParam("id") int id) {
userRepository.deleteById(id);
return "redirect:/user/list";
}
}
このdeleteUserメソッドでIDを受け取り、RepositoryのdeleteByIdメソッドに渡しています。そして、削除後はユーザー一覧ページへリダイレクトします。
続いて、Repositoryの実装です。JDBCを使ってSQLのDELETE文を実行します。
@Repository
public class UserRepository {
@Autowired
private JdbcTemplate jdbcTemplate;
public void deleteById(int id) {
String sql = "DELETE FROM users WHERE id = ?";
jdbcTemplate.update(sql, id);
}
}
JdbcTemplateを使うことで、直接SQLを実行し、プレースホルダー?にIDをバインドできます。これにより、SQLインジェクションのリスクも回避できます。
このように、画面でボタンを押すとControllerが動き、RepositoryがDELETE文を実行してくれる流れが完成します。
ここまでで、DELETE文を使ったSpringでのデータ削除の基本的な仕組みが理解できたかと思います。
3. HTMLとControllerの連携:削除リンクとパラメータの受け渡し
前回の説明では、削除処理の全体の流れとして「画面 → Controller → Repository」のステップを紹介しました。ここではまず、HTML側からControllerにidを渡す方法をさらに詳しく解説します。
HTMLでは、ユーザー一覧のテーブルを表示し、それぞれの行に「削除」リンクを配置することで、対象のユーザーを削除できるようにします。
<table>
<tr>
<th>ID</th><th>名前</th><th>操作</th>
</tr>
<tr>
<td>1</td><td>山田太郎</td>
<td><a href="/user/delete?id=1">削除</a></td>
</tr>
<tr>
<td>2</td><td>佐藤花子</td>
<td><a href="/user/delete?id=2">削除</a></td>
</tr>
</table>
このように、削除リンクには?id=〇の形式でユーザーIDを含めます。Springの@Controllerクラスでは、このidを@RequestParamアノテーションで受け取ります。
@GetMapping("/user/delete")
public String deleteUser(@RequestParam("id") int id) {
userRepository.deleteById(id);
return "redirect:/user/list";
}
このようにしてURLパラメータでIDを送信することで、特定のユーザーに対する削除処理が可能になります。フォームを使わず、シンプルなリンク形式であればGETメソッドでも動作します。
ただし、GETメソッドでデータを削除するのはセキュリティ上の懸念もあるため、本番環境ではPOSTやDELETEメソッドを検討することも重要です。今回は初心者向けのサンプルとして、わかりやすさを優先したGET形式を採用しています。
4. RepositoryでのDELETE処理の実装:アノテーションと安全なSQL
Repositoryでは、JDBCを使ってDELETE文を実行します。Springでは@Repositoryをつけたクラスにデータアクセスの責任を持たせるのが一般的です。
まずは基本の実装から見てみましょう。
@Repository
public class UserRepository {
@Autowired
private JdbcTemplate jdbcTemplate;
public void deleteById(int id) {
String sql = "DELETE FROM users WHERE id = ?";
jdbcTemplate.update(sql, id);
}
}
JdbcTemplateを使うことで、SQL文とプレースホルダー?を組み合わせて、安全にSQLを実行できます。変数idの値はバインドされるため、SQLインジェクション対策も万全です。
また、トランザクション処理が必要な場合は、@Transactionalアノテーションを使うことで、複数のDB操作を1つのトランザクションとして扱うことができます。
@Repository
@Transactional
public class UserRepository {
@Autowired
private JdbcTemplate jdbcTemplate;
public void deleteById(int id) {
String sql = "DELETE FROM users WHERE id = ?";
jdbcTemplate.update(sql, id);
}
}
このように@Transactionalをつけることで、もしこの中の処理で例外が発生した場合、自動的にロールバックが行われるようになります。今回はDELETE文1つだけですが、将来的に複数の操作が連動するような処理に発展した場合でも安心して使えます。
なお、削除処理では特に「指定したIDが本当に存在するか」のチェックが重要です。存在しないIDでDELETEを実行してもエラーにはなりませんが、ユーザーにとっては削除できたかどうかわかりにくいため、前処理として対象のレコードの存在確認を行うとさらに丁寧です。
例えば、以下のように先にSELECTで確認し、存在しない場合は何もしない設計も可能です。
public void deleteById(int id) {
String checkSql = "SELECT COUNT(*) FROM users WHERE id = ?";
Integer count = jdbcTemplate.queryForObject(checkSql, Integer.class, id);
if (count != null && count > 0) {
String deleteSql = "DELETE FROM users WHERE id = ?";
jdbcTemplate.update(deleteSql, id);
}
}
このように、事前にレコードの存在を確認することで、ユーザーの操作ミスや悪意あるリクエストにも耐えられる堅牢な処理になります。
削除処理は、アプリケーションの信頼性にも直結する部分ですので、単にSQLを実行するだけでなく、安全性・ユーザー目線での設計も考慮することが大切です。
5. 削除処理の注意点:エラー処理と確認の工夫
DELETE文を使った削除処理は非常に便利ですが、いくつかの注意点を理解しておく必要があります。とくに初心者の方は、「存在しないIDを指定してしまう」「削除処理が失敗してもエラーが表示されない」といった状況で戸惑うことが多いです。
まず重要なのが、対象のIDが本当に存在するかどうかを確認することです。前回の説明でも紹介したように、事前にSELECT COUNT(*)で確認する方法が効果的です。
加えて、削除処理にtry-catchを取り入れることで、例外発生時にエラーをログ出力したり、ユーザーにわかりやすく伝えることができます。以下のように記述できます。
public void deleteById(int id) {
try {
String checkSql = "SELECT COUNT(*) FROM users WHERE id = ?";
Integer count = jdbcTemplate.queryForObject(checkSql, Integer.class, id);
if (count != null && count > 0) {
String deleteSql = "DELETE FROM users WHERE id = ?";
jdbcTemplate.update(deleteSql, id);
}
} catch (Exception e) {
System.out.println("削除処理中にエラーが発生しました: " + e.getMessage());
}
}
例外処理を取り入れることで、「削除できない」原因を特定しやすくなります。ログ出力だけでなく、画面側でエラーメッセージを表示する仕組みも追加すれば、ユーザーに優しい設計になります。
また、削除前に確認画面を挟む設計も有効です。例えば「本当に削除してもよろしいですか?」と確認用のページやダイアログを表示することで、誤操作を防ぐことができます。
このような一手間が、アプリケーションの品質を大きく向上させます。
6. 実行後の動作確認方法:DBと画面の更新
SpringアプリケーションでDELETE文を使って削除処理を実装したあと、必ず動作確認を行うことが重要です。以下の2つの視点で確認するようにしましょう。
- ① データベース側で本当に削除されているか
- ② 画面が正しく更新されているか
まず、データベースの状態を確認するには、SELECT * FROM users;を実行して、対象のIDが消えているかをチェックします。データベースクライアントやIDE内のSQLツールを使うと便利です。
次に、Springアプリケーションの画面側では、削除後にリスト画面へリダイレクトする処理が正しく動いているかを確認します。
Controllerでredirect:を使うことで、削除後にURLを移動し、一覧画面を再描画できます。
@GetMapping("/user/delete")
public String deleteUser(@RequestParam("id") int id) {
userRepository.deleteById(id);
return "redirect:/user/list";
}
削除後に画面がそのままの場合、古い情報が表示されたままになるため、リダイレクトは非常に重要です。
また、再描画された一覧画面で削除対象のユーザーが表示されていなければ、削除処理が成功したと判断できます。これによりユーザーも安心して操作できます。
7. よくある削除処理の失敗とその対処法
最後に、DELETE文やSpringでの削除処理で初心者がよくつまずくポイントと、その解決方法をまとめて紹介します。
(1)URLにidパラメータがない
HTMLのリンクに?id=の指定を忘れると、Controllerでエラーになります。
対策:HTMLのリンクを必ず<a href="/user/delete?id=${user.id}">のように記述しましょう。
(2)IDがnullになる
Controllerで@RequestParamで受け取るIDがnullになっている場合、URLの構造が間違っているか、name属性が一致していないケースがあります。
対策:URLの末尾に?id=数字があるかを確認してください。
(3)削除されないのにエラーが出ない
IDが存在しないままDELETE文を実行しても、SQL的には成功となり、エラーが表示されない場合があります。
対策:削除前にSELECT COUNT(*)で存在確認するようにしましょう。
(4)画面の情報が更新されない
削除しても画面上にデータが残っていると、ユーザーは削除できていないと感じてしまいます。
対策:Controllerでredirect:/user/listと記述し、削除後にリスト画面へ遷移させましょう。
(5)データベース接続が切れている
JDBCの設定やデータベースが起動していない場合、削除処理は失敗します。
対策:アプリケーションのログにエラーメッセージが出力されるため、コンソールで確認して原因を特定しましょう。
これらのトラブルは、最初のうちはよくあることです。落ち着いてログを確認し、IDの値やSQLの構文、データベースの状態を一つずつ確認することが解決への近道です。
まとめ
ここまで、Springを利用したDELETE文による削除処理の基本、画面からController、そしてRepositoryへとつながる一連の削除フロー、さらに安全なSQL実行や例外処理、削除後のリダイレクト動作確認、そして削除処理で初心者がつまずきやすいポイントについて詳しく解説しました。まとめとして、DELETE文の役割、Springにおける削除実装の流れ、安全性を高めるためのSQLインジェクション対策、存在確認の重要性、例外処理やログ出力の工夫など、削除処理に必要な多くのポイントを総合的に振り返ります。とくに、削除機能はアプリケーションの信頼性に直結する重要な操作であるため、細心の注意を払って設計することが大切です。ユーザーが安心して使える削除機能を実装するには、削除前の確認画面、エラー時の丁寧な通知、トランザクション管理、そして画面更新によるフィードバックなど、多角的な視点で品質向上を図る必要があります。また、本記事で扱ったDELETE文、@Controller、@Repository、JdbcTemplate、@Transactionalといったキーワードは、Springのバックエンド開発で頻繁に使用する重要な技術要素であり、SEO的にも検索エンジンが注目しやすい専門用語です。これらのキーワードをしっかり理解しておくことで、実務でも役立つだけでなく、学習内容の整理としても効果的です。
以下に本記事のまとめとして、削除処理の概念を復習できるサンプルプログラムを掲載します。記事内で使用したclass構造やタグに合わせ、SpringにおけるDELETE文処理の流れをわかりやすく再掲しています。
@Controller
public class SampleDeleteController {
@Autowired
private UserRepository userRepository;
@GetMapping("/sample/delete")
public String delete(@RequestParam("id") int id) {
userRepository.deleteById(id);
return "redirect:/sample/list";
}
}
@Repository
@Transactional
public class SampleDeleteRepository {
@Autowired
private JdbcTemplate jdbcTemplate;
public void deleteById(int id) {
String sqlCheck = "SELECT COUNT(*) FROM users WHERE id = ?";
Integer count = jdbcTemplate.queryForObject(sqlCheck, Integer.class, id);
if (count != null && count > 0) {
String sqlDelete = "DELETE FROM users WHERE id = ?";
jdbcTemplate.update(sqlDelete, id);
}
}
}
このような削除処理のサンプルを通じて、DELETE文の基本構造、Springでの実装方法、安全なSQL実行方法、そして削除後の画面遷移までの一連の流れを理解しやすくなります。削除機能は簡単そうに見えて、実際には誤削除やデータ消失といった重大なリスクが伴うため、実務では特に注意しながら開発を進める必要があります。DELETE文、Controller、Repository、JdbcTemplate、トランザクション、例外処理、ログ記録、確認画面などのキーワードを押さえて、より堅牢で信頼性の高いシステム構築を目指しましょう。
新人
「DELETE文ってただデータを消すだけだと思っていましたが、Springで安全に実装するにはいろいろな工夫が必要なんですね」
先輩
「そうだね。削除は取り返しがつかない操作だから、事前確認、例外処理、ログ管理などを丁寧に組み込む必要があるんだよ」
新人
「Repositoryで存在確認してからDELETEする仕組みはすごく安心できますね。SQLインジェクション対策にもなるし、間違ってIDが飛んでも安全ですよね?」
先輩
「そうそう。JdbcTemplateを使うと安全にバインドできるし、@Transactionalをつければ失敗時にロールバックできるからさらに堅牢になるよ」
新人
「削除後にリダイレクトする理由も理解できました!画面更新をしないと削除されたように見えないんですね」
先輩
「その通り。ユーザーにとってわかりやすい動作にすることも開発では大切だよ。今回のDELETE文の仕組みはバックエンドの基本だから、ぜひ覚えておいてね」