カテゴリ: SpringのDB操作 更新日: 2025/12/05

save() と saveAndFlush() の違いを完全ガイド!初心者でもわかる実装方法

save() と saveAndFlush() の違いを詳しく解説
save() と saveAndFlush() の違いを詳しく解説

新人と先輩の会話形式で理解しよう

新人

「先輩、Spring Data JPAでデータを保存する方法ってsave()saveAndFlush()がありますけど、違いは何ですか?」

先輩

「いい質問だね。どちらもデータを保存するメソッドだけど、データベースへの反映タイミングが異なるんだ。使い方を理解して適切に選ぶことが大切だよ。」

新人

「なるほど!それぞれの動作や使い分けを詳しく教えてください!」

先輩

「それじゃあ、基本的な使い方から説明していくね。」

1. save() とは?

1. save() とは?
1. save() とは?

save()メソッドは、Spring Data JPAでエンティティをデータベースに保存または更新するための基本的なメソッドです。このメソッドは、JpaRepositoryインターフェースから自動的に提供されます。

呼び出すとエンティティマネージャにデータが登録され、トランザクションがコミットされた時点でデータベースに反映されます。すぐにデータベースへ反映されるわけではなく、トランザクション終了時にまとめて反映されるのが特徴です。


import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;

@Controller
public class UserController {

    @Autowired
    private UserRepository userRepository;

    @GetMapping("/saveUser")
    public String saveUser() {
        User user = new User("田中 太郎", "tanaka@example.com");
        userRepository.save(user); // データはトランザクション終了時にDBへ反映
        return "saveResult";
    }
}

このように、save()を使うと簡単にデータの登録や更新が行えますが、即時反映を必要としない場合に使うのが一般的です。

2. saveAndFlush() とは?

2. saveAndFlush() とは?
2. saveAndFlush() とは?

saveAndFlush()メソッドは、save()と同じようにエンティティを保存または更新しますが、呼び出した直後にデータベースへ即時反映される点が異なります。内部的にflush()メソッドが実行され、永続コンテキスト内の変更が強制的に同期されます。

データベースへの即時反映が必要な場面(他のトランザクションで直後にデータを参照する場合や、すぐに反映された結果を取得したい場合)に有効です。


import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;

@Controller
public class UserController {

    @Autowired
    private UserRepository userRepository;

    @GetMapping("/saveAndFlushUser")
    public String saveAndFlushUser() {
        User user = new User("佐藤 花子", "sato@example.com");
        userRepository.saveAndFlush(user); // 即時にデータベースへ反映される
        return "saveAndFlushResult";
    }
}

即時反映が求められる場面ではsaveAndFlush()を使うのが適切です。しかし、無駄に多用するとパフォーマンスに悪影響を与えることがあるため、用途に応じて使い分けましょう。

3. save() の実装例と使いどころ

3. save() の実装例と使いどころ
3. save() の実装例と使いどころ

save()メソッドは、データの保存や更新において最も基本的なメソッドです。特にトランザクション内で複数の処理をまとめて実行し、最後に一括でデータベースへ反映させたい場合に便利です。

3.1 基本的な使い方


import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.GetMapping;

@Controller
public class UserController {

    @Autowired
    private UserRepository userRepository;

    @Transactional
    @GetMapping("/saveMultipleUsers")
    public String saveMultipleUsers() {
        User user1 = new User("山田 太郎", "yamada@example.com");
        User user2 = new User("鈴木 花子", "suzuki@example.com");

        userRepository.save(user1);
        userRepository.save(user2);

        // トランザクションが終了するタイミングでDBに反映される
        return "saveMultipleResult";
    }
}

上記コードでは、複数のsave()メソッドが呼ばれていますが、トランザクションが終了するまでデータベースへの書き込みは遅延されます。これによりパフォーマンスが向上します。

3.2 save() の使いどころ

  • 複数のデータをまとめて保存・更新したい場合
  • パフォーマンスを重視し、データベースへのアクセス回数を減らしたい場合
  • トランザクション管理下で処理をまとめたい場合

4. saveAndFlush() の実装例と使いどころ

4. saveAndFlush() の実装例と使いどころ
4. saveAndFlush() の実装例と使いどころ

saveAndFlush()はデータを即時にデータベースへ反映させるため、特定の状況で有効です。たとえば、保存した直後にデータベース上の最新データを参照する必要がある場合や、他のトランザクションがデータをすぐに参照する場合に使用します。

4.1 基本的な使い方


import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;

@Controller
public class UserController {

    @Autowired
    private UserRepository userRepository;

    @GetMapping("/saveAndFlushExample")
    public String saveAndFlushExample() {
        User user = new User("高橋 健", "takahashi@example.com");
        userRepository.saveAndFlush(user); // 即座にDBへ反映
        return "saveAndFlushResult";
    }
}

このメソッドを使用すると、トランザクション内であってもその場でデータがデータベースに書き込まれるため、直後の処理で確実に最新データを取得できます。

4.2 saveAndFlush() の使いどころ

  • 保存後すぐにデータを他の処理で参照したい場合
  • 異なるトランザクションでデータの一貫性が求められる場合
  • デバッグや確認のため、即座にDB反映が必要な場合

5. save() と saveAndFlush() の実際の動作比較

5. save() と saveAndFlush() の実際の動作比較
5. save() と saveAndFlush() の実際の動作比較

ここでは、save()saveAndFlush()の動作の違いを具体的なコードと結果で比較します。

5.1 比較用コード


import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
public class ComparisonController {

    @Autowired
    private UserRepository userRepository;

    @GetMapping("/compareSave")
    @ResponseBody
    public String compareSave() {
        User user1 = new User("佐々木 次郎", "sasaki@example.com");
        userRepository.save(user1); // DB反映はトランザクション終了時

        User foundUser = userRepository.findByEmail("sasaki@example.com");
        return foundUser != null ? "ユーザーが見つかりました" : "ユーザーが見つかりません";
    }

    @GetMapping("/compareSaveAndFlush")
    @ResponseBody
    public String compareSaveAndFlush() {
        User user2 = new User("中村 三郎", "nakamura@example.com");
        userRepository.saveAndFlush(user2); // 即時反映

        User foundUser = userRepository.findByEmail("nakamura@example.com");
        return foundUser != null ? "ユーザーが見つかりました" : "ユーザーが見つかりません";
    }
}

5.2 実行結果

/compareSave にアクセスした場合:


ユーザーが見つかりません

save()ではデータベース反映が遅延されるため、直後の検索では見つかりません。

/compareSaveAndFlush にアクセスした場合:


ユーザーが見つかりました

saveAndFlush()では即座に反映されるため、すぐに検索結果に反映されます。

5.3 違いのまとめ

メソッド DB反映タイミング 使うべき場面
save() トランザクション終了時 複数の処理をまとめて効率的に保存したい場合
saveAndFlush() メソッド実行直後 即時にデータ反映が必要な場合

このように、目的やシチュエーションに応じて適切にメソッドを選ぶことが大切です。

6. save() と saveAndFlush() の違いのまとめ

6. save() と saveAndFlush() の違いのまとめ
6. save() と saveAndFlush() の違いのまとめ

save()saveAndFlush()はどちらもSpring Data JPAでデータを保存・更新するためのメソッドですが、主な違いはデータベースへの反映タイミングです。

6.1 違いの比較表

メソッド DB反映タイミング 主な使いどころ
save() トランザクション終了時 複数処理をまとめて実行し、効率よく保存したい場合
saveAndFlush() メソッド実行直後 即時にデータ反映が必要な場合や、保存直後にデータを参照したい場合

このように、save()はパフォーマンスを意識した通常の保存処理に適しており、saveAndFlush()は即時反映が求められる特殊なケースで有効です。

7. どちらを選ぶべきかの判断基準

7. どちらを選ぶべきかの判断基準
7. どちらを選ぶべきかの判断基準

プロジェクトや処理内容によって、save()saveAndFlush()のどちらを選択するべきかが変わります。以下のポイントを参考に判断しましょう。

7.1 save() を選ぶべきケース

  • パフォーマンスを優先したいとき
  • トランザクション内で複数の保存処理をまとめたいとき
  • 一度に多くのデータを登録・更新したいとき
  • 即時反映が必要ない通常の保存処理の場合

7.2 saveAndFlush() を選ぶべきケース

  • データ保存後すぐにデータベースから最新情報を取得したいとき
  • 他のトランザクションで直後にデータ参照が必要なとき
  • テストやデバッグで、保存結果を即座に確認したいとき
  • 特定の処理でデータ整合性を即時に保証する必要がある場合

8. よくあるエラーとその対処方法

8. よくあるエラーとその対処方法
8. よくあるエラーとその対処方法

save()saveAndFlush()を使用する際には、いくつかのよくあるエラーが発生することがあります。以下に代表的なエラーと対処方法を紹介します。

8.1 エラー1: DataIntegrityViolationException

原因: データベースの制約違反(ユニーク制約、NULL制約など)により発生します。


org.springframework.dao.DataIntegrityViolationException: could not execute statement; SQL [n/a]; constraint [UK_EMAIL];

対処方法:

  • エンティティのアノテーション(@Column(nullable = false)@Column(unique = true))を確認。
  • 保存前に既存データがないか確認する(findByEmail()などで事前チェック)。

8.2 エラー2: TransactionRequiredException

原因: トランザクションが必要な操作にトランザクションが存在しない場合に発生します。


javax.persistence.TransactionRequiredException: Executing an update/delete query

対処方法:

  • メソッドに@Transactionalアノテーションを追加。
  • トランザクション管理が正しく行われているか確認。

8.3 エラー3: LazyInitializationException

原因: エンティティの遅延ロードに関連するフィールドにトランザクション外からアクセスした場合に発生します。


org.hibernate.LazyInitializationException: could not initialize proxy - no Session

対処方法:

  • @Transactionalの範囲内でデータを参照。
  • 必要に応じてフェッチタイプをFetchType.EAGERに変更。

8.4 エラー4: OptimisticLockException

原因: 楽観的ロックで同時更新時にバージョン不一致が発生。


javax.persistence.OptimisticLockException: Row was updated or deleted by another transaction

対処方法:

  • @Versionアノテーションをエンティティに追加し、バージョン管理を有効化。
  • 競合が発生しないように処理順序を見直す。

8.5 エラー5: InvalidDataAccessApiUsageException

原因: 非管理エンティティを保存しようとする場合に発生。


org.springframework.dao.InvalidDataAccessApiUsageException: Not an entity: class com.example.User

対処方法:

  • エンティティクラスに@Entityアノテーションが付いているか確認。
  • 正しいリポジトリを使用しているか確認。

まとめ

まとめ
まとめ

Spring Data JPA における save()saveAndFlush() の違いは、エンティティを保存したタイミングでデータベースに反映されるかどうかという、開発現場で非常に重要な性質に直結します。この記事全体を通じて、両者の動作の違いや使い分けの基準、実際のコード例や挙動の比較を確認しながら、初心者でも理解しやすいかたちで知識を積み上げられるように整理してきました。アプリケーションの構造によっては、データベースへの反映タイミングが想像以上に大切な意味を持つことがあり、特に複数の処理が複雑に絡み合うプロジェクトではさらに慎重な判断が求められます。

save() はトランザクション終了までデータベースに書き込まず、複数処理をまとめて扱う際に効率性を保つ使い方が理想的です。一方、saveAndFlush() は即時反映が必須の場面、または保存直後に別の処理が同じデータを参照する場合に力を発揮します。この違いを理解したうえで適切に選択できると、意図したデータ整合性を保ちつつ、パフォーマンスを安定させる設計がしやすくなります。また、例外の扱い、トランザクション管理、エンティティの制約など、エラーが起こりやすいポイントにも触れました。実務に近い視点で学ぶことで、どの段階でどのメソッドを使うべきかの判断がより自然にできるようになるはずです。

振り返りのサンプルコード


package com.example.demo.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;

@Controller
public class ReviewController {

    @Autowired
    private UserRepository userRepository;

    @GetMapping("/reviewSaveExample")
    public String reviewSaveExample() {
        User user = new User("復習 太郎", "fukushu@example.com");
        userRepository.save(user); // トランザクション終了時に反映される保存処理
        return "reviewSaveResult";
    }

    @GetMapping("/reviewSaveAndFlushExample")
    public String reviewSaveAndFlushExample() {
        User user = new User("即時 花子", "sokujihanako@example.com");
        userRepository.saveAndFlush(user); // 即時DBへ反映
        return "reviewSaveAndFlushResult";
    }
}

このように、保存処理のタイミングを選択するだけでもアプリケーションの動作が大きく変わります。処理が重なり合うような画面では、即時反映が必要なのか、それとも一括処理で効率化を優先すべきなのかを落ち着いて判断することが大切です。特に、大規模な更新処理や複数ユーザーが同時に操作するシステムでは、小さな判断がデータ整合性に影響することも珍しくありません。こうした細かい技術背景を理解しておくことで、安定したアプリケーション設計に近づけます。 また、Spring Data JPA が提供するメソッドは多岐にわたりますが、基礎である save()saveAndFlush() のしくみを理解しておくことで、今後より高度な JPA の知識を積み上げる際にも大きな助けとなります。

先生と生徒の振り返り会話

生徒:「今日の話で、save()saveAndFlush() の違いがかなりはっきり理解できました。反映されるタイミングってこんなに大事なんですね。」

先生:「そうだね。特にデータを即時に確認したい処理や、他のトランザクションとの連携がある場面では、どちらを選ぶかで結果が変わることがあるんだよ。」

生徒:「確かに、比較のコードで検索結果に差が出ていたのを見て納得しました。実際の動作で違いが見えるとイメージしやすいです。」

先生:「実務では、効率を優先したいときはsave()、確実にすぐ反映させたいときはsaveAndFlush() と覚えておくと良いよ。よくあるエラーも一緒に覚えておくと、トラブルの原因をすぐに見つけやすくなるはずだ。」

生徒:「例外の種類や原因も整理されていて助かりました。これから実装する時に迷わず選べそうです。」

先生:「いいね。理解が進んでいる証拠だよ。今回の内容を活かして、より堅牢な保存処理を設計できるように意識してみてね。」

生徒:「はい、ありがとうございます!実際のコードでも試しながら理解を深めます!」

この記事を読んだ人からの質問

この記事を読んだ人からの質問
この記事を読んだ人からの質問

プログラミング初心者からのよくある疑問/質問を解決します

Spring Data JPA の save() メソッドは、いつデータベースに反映されますか?

save() メソッドを使って保存されたデータは、トランザクションの終了時にデータベースに反映されます。すぐには反映されず、一括でコミットされるのが特徴です。
コメント
コメント投稿は、ログインしてください

まだ口コミはありません。

関連記事:

関連記事なし

カテゴリの一覧へ
新着記事
New1
Spring認証(Spring Security)
Spring BootでCORSを設定する方法を完全解説!初心者でもわかるセキュリティ対策
New2
Spring認証(Spring Security)
パスワードをハッシュ化する理由とは?セキュリティ対策の基本をSpring Securityで学ぼう
New3
SpringのWeb開発(Spring MVC)
HTTPリクエストとレスポンスの基本を完全解説!Spring MVC初心者がWeb通信の仕組みをやさしく理解
New4
Spring認証(Spring Security)
ブラウザからのフォーム送信とは?HTTPリクエストの基礎を初心者向けに解説!
人気記事
No.1
Java&Spring記事人気No1
SpringのWeb開発(Spring MVC)
ルーティングとは?基本概念(Spring MVCのURL制御を理解)
No.2
Java&Spring記事人気No2
Thymeleaf
Thymeleaf とは?初心者向けにThymeleafの基本を徹底解説
No.3
Java&Spring記事人気No3
Springの基本
application.properties と YAML の基本をやさしく解説!初心者向けSpring Boot設定ファイル入門
No.4
Java&Spring記事人気No4
Springの基本
Spring Bootのデフォルトログ設定を徹底解説(Logback / SLF4J)
No.5
Java&Spring記事人気No5
Springの基本
Spring Bootの環境変数の設定方法をやさしく解説!初心者向けapplication.propertiesの使い方
No.6
Java&Spring記事人気No6
SpringのWeb開発(Spring MVC)
ループ処理(th:each)の基本を完全ガイド!Thymeafの繰り返し処理の使い方
No.7
Java&Spring記事人気No7
SpringのDB操作
JPAの標準クエリメソッド(findById, findAll)を完全解説!初心者でもわかるデータ取得の基本
No.8
Java&Spring記事人気No8
Spring認証(Spring Security)
セッション管理の基本(@SessionAttributes)を完全解説!初心者でもわかるセッションの仕組み