JavaのSpring Data JPAでデータを保存・更新・削除する方法!初心者向けガイド
生徒
「Spring Data JPAを使ってデータベースにデータを保存する方法を教えてください!」
先生
「もちろんです!Spring Data JPAでは、データの保存や更新、削除が簡単にできます。saveメソッドとdeleteByIdメソッドの使い方を詳しく見ていきましょう。」
生徒
「それは便利ですね!基本的な使い方を知りたいです。」
先生
「では、順を追って具体的に解説しますね。」
1. Spring Data JPAでデータを保存する方法(saveメソッド)
まずは「新しいレコードを1件追加する」いちばん基本の流れです。Spring Data JPAでは、エンティティ(ここではUser)を作って
Repositoryのsaveに渡すだけ。IDを自動採番している場合、IDがnullのエンティティは新規追加として保存されます。
実装は「リポジトリを用意 → コントローラで受け取った値を詰める → save呼び出し」の3ステップで完了します。
import org.springframework.data.jpa.repository.JpaRepository;
// Userエンティティ用のリポジトリ。実装はSpringが自動生成します。
public interface UserRepository extends JpaRepository<User, Integer> {
}
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
@Controller
public class UserController {
@Autowired
private UserRepository userRepository;
// 例: /users/create?username=taro&email=taro@example.com
@GetMapping("/users/create")
public String createUser(@RequestParam String username,
@RequestParam String email,
Model model) {
// 1) 入力値からエンティティを作成
User user = new User();
user.setUsername(username);
user.setEmail(email);
// 2) saveで保存(IDがnullなのでINSERTされる)
User saved = userRepository.save(user);
// 3) 結果を画面に渡す(採番されたIDも取得できる)
model.addAttribute("message", "User created successfully (id=" + saved.getId() + ")");
return "result";
}
}
実行の感触をつかむコツとして、まずはブラウザでURLに名前とメールを付けて叩き、保存後に返ってくるIDを画面で確認してみてください。saveは保存した実体を返すので、そのままメッセージに埋め込めます。未入力だと空文字のまま登録される点は注意(最初は動かすことを優先し、入力チェックはあとから段階的に足すのがおすすめ)。また今回は手早く試すためにGETを使っていますが、フォーム投稿としてはPOSTを使うのが一般的です。まずは小さく通して仕組みを理解し、必要になったらバリデーションや画面設計を整える、という順番で進めると学習がスムーズです。
2. Spring Data JPAでデータを更新する方法(saveメソッド)
既存のデータを更新する場合もsaveメソッドを使います。更新したいエンティティのIDを指定し、必要なプロパティを更新してからsaveメソッドで保存します。例えば、ユーザーの情報を更新する場合、次のようにします。
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
@Controller
public class UserController {
@Autowired
private UserRepository userRepository;
@GetMapping("/users/update")
public String updateUser(@RequestParam Integer id, @RequestParam String username, @RequestParam String email, Model model) {
User user = userRepository.findById(id).get();
user.setUsername(username);
user.setEmail(email);
userRepository.save(user);
model.addAttribute("message", "User updated successfully");
return "result";
}
}
このコードでは、/users/updateエンドポイントにid, usernameおよびemailパラメータを渡すことで指定したIDのユーザー情報が更新されます。
将来を見据えて、+αのスキルを身につけたい方へ
JavaやLinuxを学んでいても、「このままで市場価値は上がるのか」 「キャリアの選択肢を広げたい」と感じる方は少なくありません。
AIを学ぶならアイデミープレミアム3. Spring Data JPAでデータを削除する方法(deleteByIdメソッド)
データを削除するには、deleteByIdメソッドを使用します。このメソッドは、指定したIDのデータをデータベースから削除します。以下のコード例では、指定したIDのユーザーを削除します。
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
@Controller
public class UserController {
@Autowired
private UserRepository userRepository;
@GetMapping("/users/delete")
public String deleteUser(@RequestParam Integer id, Model model) {
userRepository.deleteById(id);
model.addAttribute("message", "User deleted successfully");
return "result";
}
}
このコードでは、/users/deleteエンドポイントにidパラメータを渡すことで、該当のIDのユーザーが削除されます。
4. saveの挙動と「新規/更新」の判定・まとめて保存(saveAll/saveAndFlush)
Spring Data JPAのsaveはアップサート(insert or update)として動作します。通常、@GeneratedValueでIDを自動採番している場合は、IDが未設定(null)なら新規保存、既存IDが紐づくなら更新になります。大量データはsaveAllでまとめて登録し、即時にDBへ反映したい場面ではsaveAndFlushが便利です(大量処理ではバッチ設定も検討)。
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import java.util.List;
import java.util.Arrays;
@Controller
public class UserBulkController {
@Autowired
private UserRepository userRepository;
// まとめて新規保存(アップサート)
@GetMapping("/users/bulkCreate")
public String bulkCreate(Model model) {
List<User> users = Arrays.asList(
new User(null, "taro", "taro@example.com"),
new User(null, "hanako", "hanako@example.com")
);
userRepository.saveAll(users);
model.addAttribute("message", "Users created (bulk)");
return "result";
}
}
補足:更新は「永続化コンテキスト」に管理されたエンティティなら、@Transactional内でプロパティを書き換えるだけでダーティチェッキングにより自動反映されます(明示save不要)。
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Service
public class UserWriteService {
private final UserRepository repo;
public UserWriteService(UserRepository repo) { this.repo = repo; }
@Transactional
public void rename(Integer id, String newName) {
User u = repo.findById(id).orElseThrow(() -> new IllegalArgumentException("not found"));
u.setUsername(newName); // トランザクション終了時に自動UPDATE
}
}
5. 削除のベストプラクティス(deleteById/関連のカスケード/論理削除)
deleteByIdは最もシンプルな物理削除です。ただし親子関係(@OneToManyなど)がある場合、外部キー制約でエラーになりがちなので、cascade = CascadeType.REMOVEやorphanRemoval = trueを設計段階で検討します。履歴保持が必要なら論理削除(ソフトデリート)のフラグを導入し、検索時は未削除のみを返すクエリメソッドを用意します。
import jakarta.persistence.*;
import java.util.List;
@Entity
public class User {
@Id @GeneratedValue
private Integer id;
private String username;
private String email;
private boolean deleted = false; // 論理削除フラグ
@OneToMany(mappedBy = "user", cascade = CascadeType.REMOVE, orphanRemoval = true)
private List<Post> posts;
// getter/setter 省略
}
public interface UserRepository extends JpaRepository<User, Integer> {
// 論理削除対応の検索
List<User> findByDeletedFalse();
}
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
@Controller
public class UserDeleteController {
@Autowired
private UserRepository userRepository;
// 物理削除
@GetMapping("/users/remove")
public String remove(@RequestParam Integer id, Model model) {
userRepository.deleteById(id); // 存在しないIDは例外になる場合あり
model.addAttribute("message", "User deleted");
return "result";
}
// 論理削除
@GetMapping("/users/softDelete")
public String softDelete(@RequestParam Integer id, Model model) {
User u = userRepository.findById(id).orElse(null);
if (u == null) {
model.addAttribute("message", "User not found");
return "result";
}
u.setDeleted(true); // フラグのみ更新
userRepository.save(u);
model.addAttribute("message", "User soft-deleted");
return "result";
}
}
SEO・UXの観点では、「削除後のリダイレクト先」や「確認ダイアログ」も重要です。誤操作防止のため、確認画面→実行の二段階にすると安心です(実運用ではHTTPメソッドもDELETE/POSTに分離)。
6. 保存・更新・削除で起きやすい例外と対策(@Transactional/一意制約/同時更新)
CRUD実装では例外処理とトランザクション境界が品質を左右します。代表的には、DataIntegrityViolationException(一意制約やFK制約違反)、EmptyResultDataAccessException(存在しないIDをdeleteById)など。@Transactionalで一連の保存・更新・削除をまとめ、発生時はロールバックしてユーザーに分かりやすいメッセージを返します。
import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.dao.EmptyResultDataAccessException;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
@Controller
public class SafeCrudController {
private final UserWriteService service;
public SafeCrudController(UserWriteService service) { this.service = service; }
@GetMapping("/users/safeRename")
public String safeRename(Integer id, String username, Model model) {
try {
service.rename(id, username);
model.addAttribute("message", "User updated (tx committed)");
} catch (IllegalArgumentException e) {
model.addAttribute("message", "User not found");
} catch (DataIntegrityViolationException e) {
model.addAttribute("message", "Constraint violation");
}
return "result";
}
@GetMapping("/users/safeDelete")
public String safeDelete(Integer id, Model model) {
try {
service.delete(id);
model.addAttribute("message", "User deleted");
} catch (EmptyResultDataAccessException e) {
model.addAttribute("message", "User already removed or not found");
}
return "result";
}
}
同時更新の競合には楽観的ロック(@Version)が有効です。更新時にバージョン不一致を検知して例外を投げ、ユーザーに「他で更新されました」と再入力を促します。これにより「更新の取りこぼし」を防ぎ、タイトル通りの保存・更新・削除を堅牢に実装できます。
まとめ
この記事では、Spring Data JPAを使ってデータベースにデータを保存、更新、削除する方法について解説しました。saveメソッドとdeleteByIdメソッドを使用することで、初心者でも簡単にCRUD操作を実現できます。Spring Data JPAは、SQLを直接書かなくてもデータ操作ができる点で非常に便利であり、開発効率を大幅に向上させます。
特に、saveメソッドは新規データの追加だけでなく、既存データの更新にも利用できるため、柔軟性に優れています。一方で、deleteByIdメソッドを使えば、特定のIDのデータを簡単に削除することが可能です。これにより、エンティティの管理が非常にシンプルになります。
また、Spring BootのControllerクラスを使用してエンドポイントを作成し、データベース操作をHTTPリクエスト経由で行う方法も学びました。これにより、ウェブアプリケーションのバックエンドでデータ操作を簡単に実装できます。以下に、今回の記事で紹介した主要なコード例をまとめました。
<!-- Userエンティティ -->
import jakarta.persistence.Entity;
import jakarta.persistence.Id;
@Entity
public class User {
@Id
private Integer id;
private String username;
private String email;
// Getter, Setter
}
<!-- UserRepositoryインターフェース -->
import org.springframework.data.jpa.repository.JpaRepository;
public interface UserRepository extends JpaRepository<User, Integer> {
}
<!-- UserControllerクラス -->
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
@Controller
public class UserController {
@Autowired
private UserRepository userRepository;
@GetMapping("/users/create")
public String createUser(@RequestParam String username, @RequestParam String email, Model model) {
User user = new User();
user.setUsername(username);
user.setEmail(email);
userRepository.save(user);
model.addAttribute("message", "User created successfully");
return "result";
}
@GetMapping("/users/update")
public String updateUser(@RequestParam Integer id, @RequestParam String username, @RequestParam String email, Model model) {
User user = userRepository.findById(id).get();
user.setUsername(username);
user.setEmail(email);
userRepository.save(user);
model.addAttribute("message", "User updated successfully");
return "result";
}
@GetMapping("/users/delete")
public String deleteUser(@RequestParam Integer id, Model model) {
userRepository.deleteById(id);
model.addAttribute("message", "User deleted successfully");
return "result";
}
}
これらのコードを参考にすることで、Spring Data JPAを活用したCRUD操作の基本をマスターすることができます。また、HTTPリクエストと連携することで、ウェブアプリケーションに必要なデータ操作機能を簡単に実現可能です。ぜひ、実際のプロジェクトで活用してみてください。
生徒
「Spring Data JPAのsaveメソッドって、データの保存だけでなく、更新にも使えるんですね!便利です。」
先生
「その通りです。新規追加も更新も同じメソッドで対応できるのは、Spring Data JPAの強みです。ただし、IDの指定を間違えないように気をつけましょう。」
生徒
「データ削除も簡単ですね。deleteByIdを使うだけなんて驚きました!」
先生
「そうですね。ただし、削除する前に、本当に必要な操作かを確認する仕組みを追加すると、さらに安全になります。」
生徒
「これなら、簡単なCRUDアプリケーションをすぐに作れそうです。次は、もっと複雑な機能に挑戦したいです!」
先生
「いいですね。次回はリレーショナルデータベースの操作や、カスタムクエリについて詳しく学びましょう!」
この記事を読んだ人からの質問
プログラミング初心者からのよくある疑問/質問を解決します
Spring Data JPAのsaveメソッドは新規作成と更新のどちらに使えますか?
saveメソッドは、新しいデータの作成と既存データの更新の両方に使用できます。新規データの場合はIDを設定せずに保存し、更新の場合は対象データのIDを指定して保存します。
deleteByIdメソッドを使うとき、対象のデータが存在しない場合はどうなりますか?
deleteByIdメソッドを実行すると、対象データが存在しない場合に例外がスローされます。実行前に存在を確認する方法を追加すると安全です。
findByIdメソッドでデータが見つからない場合はどう処理しますか?
findByIdメソッドはOptionalを返すため、データが見つからない場合はisPresentでチェックしたり、orElseThrowを使ってカスタム例外をスローできます。
Spring Bootプロジェクトでデータベース接続情報を設定するにはどうすればいいですか?
データベース接続情報はapplication.propertiesまたはapplication.ymlに記載します。例えば、MySQLを使う場合はURL、ユーザー名、パスワードを設定します。
データベースの初期データを登録するにはどうすればいいですか?
初期データはsrc/main/resourcesディレクトリにdata.sqlファイルを配置することで、自動的に登録されます。テーブル作成はschema.sqlファイルを使用します。
saveメソッドで更新を行う際、他のフィールドの値を変更せずに維持するにはどうすればいいですか?
findByIdでエンティティを取得し、必要なフィールドのみを変更してからsaveメソッドを呼び出します。これにより、他のフィールドの値は維持されます。
Spring Data JPAで複数のエンティティを一括削除する方法はありますか?
リポジトリのdeleteAllメソッドを使用すると、全データを一括削除できます。また、deleteAllInBatchを使えば、バッチ処理で効率的に削除可能です。
saveメソッドを使った操作で同時実行制御を行うにはどうすればいいですか?
@Transactionalアノテーションを使用してトランザクション管理を行うことで、同時実行制御を適用できます。また、必要に応じてロック機構を追加することも可能です。
Spring Data JPAでのエラーハンドリングのベストプラクティスは何ですか?
例外をキャッチして適切なレスポンスを返すために、@ControllerAdviceを使用してカスタム例外ハンドラを作成するのがおすすめです。
Spring Data JPAでカスタムクエリを作成するにはどうすればいいですか?
@Queryアノテーションをリポジトリメソッドに追加することで、カスタムSQLを記述できます。JPQLやネイティブクエリもサポートされています。
Spring FrameworkやThymeleafを使った Webアプリ開発の全体像をやさしく理解したい人には、 この入門書が定番です。
Spring Framework超入門をAmazonで見る※ Amazonアソシエイト・プログラムを利用しています