カテゴリ: Spring 更新日: 2026/01/17

Springでバルク更新・一括挿入を高速に!flush・clearの使い方と最適化のベストプラクティス

バルク更新/一括挿入の注意点:フラッシュ・クリアと高速化ベストプラクティス
バルク更新/一括挿入の注意点:フラッシュ・クリアと高速化ベストプラクティス

先生と生徒の会話形式で理解しよう

生徒

「Spring Bootで大量データを一括登録したいんですけど、普通にsave()を繰り返すだけじゃダメなんですか?」

先生

「確かにそれでも動くけど、パフォーマンスは落ちるし、メモリも無駄に使ってしまいます。flush()clear()を使って、効率的に処理する方法があるんですよ。」

生徒

「flushとclearって聞いたことはあるけど、いまいち意味がわからなくて…」

先生

「それなら、一括挿入やバルク更新の注意点とあわせて、パフォーマンスを上げるベストプラクティスを丁寧に解説していきましょう!」

1. Springにおけるバルク処理とは?

1. Springにおけるバルク処理とは?
1. Springにおけるバルク処理とは?

バルク処理とは、大量のレコードを一括で登録・更新・削除する処理のことです。Spring Data JPAでも、通常のsave()delete()メソッドを使ってバルク処理はできますが、ループ処理のまま実行すると性能が大幅に劣化します。

それは、エンティティがすべてPersistenceContextに保持され、メモリ消費が増えるためです。さらに、flushのタイミングが遅れることで、データベースへの反映が遅延することもあります。

2. flushとclearの基本:高速化の鍵

2. flushとclearの基本:高速化の鍵
2. flushとclearの基本:高速化の鍵

flushは、エンティティの変更を即座にデータベースに反映させる命令です。clearは、エンティティマネージャが管理しているキャッシュ(1次キャッシュ)をクリアしてメモリを解放する命令です。

これらを適切に組み合わせることで、一括挿入やバルク更新時のパフォーマンスを飛躍的に向上させることができます。

3. saveAllだけでは不十分?バルク挿入の落とし穴

3. saveAllだけでは不十分?バルク挿入の落とし穴
3. saveAllだけでは不十分?バルク挿入の落とし穴

Spring Data JPAのsaveAll()は便利ですが、内部ではEntityManager.persist()が1件ずつ呼ばれており、flushもclearも自動で呼ばれないため、大量データには向いていません。

そこで、batchSizeごとにflush()clear()を呼ぶように手動で制御する必要があります。


@Autowired
private EntityManager entityManager;

@Transactional
public void bulkInsert(List<User> users) {
    for (int i = 0; i < users.size(); i++) {
        entityManager.persist(users.get(i));
        if (i % 50 == 0) {
            entityManager.flush();
            entityManager.clear();
        }
    }
}

このように、一定件数ごとに明示的にflush/clearを行うことで、メモリリーク防止・性能向上を両立できます。

4. バルク更新の注意点と副作用

4. バルク更新の注意点と副作用
4. バルク更新の注意点と副作用

JPAでは、JPQLで直接UPDATE文を発行するバルク更新が可能ですが、この場合PersistenceContextの内容と実際のデータベースの状態が一致しなくなります。


@Modifying
@Query("UPDATE User u SET u.status = 'ACTIVE' WHERE u.lastLogin < :threshold")
int activateUsers(@Param("threshold") LocalDateTime threshold);

このようなバルク更新を行ったあとに、同じエンティティを参照しようとすると古い値が返ることがあるため、必要に応じてclear()や再取得が必要です。

5. 高速化のためのJPAプロパティ設定

5. 高速化のためのJPAプロパティ設定
5. 高速化のためのJPAプロパティ設定

JPAのパフォーマンスを最適化するために、Hibernateのbatchサイズを設定するのが効果的です。


spring.jpa.properties.hibernate.jdbc.batch_size=50
spring.jpa.properties.hibernate.order_inserts=true
spring.jpa.properties.hibernate.order_updates=true

これにより、Hibernateが内部的にバッチ処理を最適化して、SQLの発行回数を大幅に削減してくれます。

6. Repository vs EntityManager:どちらを使うべき?

6. Repository vs EntityManager:どちらを使うべき?
6. Repository vs EntityManager:どちらを使うべき?

Spring DataのCrudRepositoryJpaRepositoryはシンプルで使いやすいですが、バルク処理の最適化にはEntityManagerの細かい制御が有効です。

エンティティが大量にある場面や、flushタイミングを自分で調整したいケースでは、EntityManagerを使ったほうが効率的です。

一方、通常の登録処理や小規模な更新であれば、save()saveAll()の使用で問題ありません。

7. バルク削除の実装と注意点

7. バルク削除の実装と注意点
7. バルク削除の実装と注意点

一括削除についても、deleteAll()はあまり効率が良くなく、JPQLでDELETE文を直接実行した方が速い場合があります。


@Modifying
@Query("DELETE FROM User u WHERE u.status = 'INACTIVE'")
int deleteInactiveUsers();

ただし、この方法もPersistenceContextと同期が取れなくなるため、必要ならflushやclearで整合性を保つのが重要です。

8. バルク処理でトランザクションと例外に注意

8. バルク処理でトランザクションと例外に注意
8. バルク処理でトランザクションと例外に注意

大量データを扱うと、途中で例外が発生したときのロールバックにも気をつける必要があります。

@Transactionalを付けて一括で処理する場合、どこかで例外が発生すると、すべてロールバックされるため、適切な単位でトランザクションを分割するのが安全です。

リトライ処理や、障害発生時のログ記録などもあらかじめ設計に組み込んでおきましょう。

まとめ

まとめ
まとめ

Springにおけるバルク処理や一括挿入・一括更新は、アプリケーションのパフォーマンス向上に直結する非常に重要な技術です。特に大量データを扱うシステムでは、単純にsaveを繰り返してしまうだけではメモリの無駄遣いや処理速度の低下につながり、想定よりも大きな負荷を招くことがあります。この記事で紹介されていたように、バルク処理の最適化にはflushとclearを適切に組み合わせて使用することが鍵となります。

flushはエンティティの変更を即時にデータベースへ反映させ、clearはPersistenceContextをクリアしてメモリ内のエンティティ管理情報を解放します。この2つを適切なタイミングで実行することで、メモリ使用量を抑えつつ処理速度を最大化することができます。とくに、大量データを一括登録する際には、一定件数ごとにflushとclearを呼ぶことで、メモリが膨れ上がるのを防ぎながらスムーズにデータ投入を進めることができます。

また、Spring Data JPAのsaveAllメソッドは便利である一方で内部的には個別にpersistが呼ばれているため、flushやclearが自動で行われない点に注意が必要です。大量データ向けにはEntityManagerを用いた明示的な制御がより効率的であり、バルク処理全体の安定性にも寄与します。加えて、バルク更新やバルク削除を行うJPQLのクエリでは、PersistenceContextとの状態不一致が発生する可能性があるため、必要に応じてclearを実行して整合性を保つことが推奨されます。

Hibernateのbatch設定やorder_inserts、order_updatesといったJPAプロパティを適切に設定することで、内部処理がさらに最適化され、SQL発行回数を大幅に削減することも可能です。これらの設定は開発者が特別なロジックを追加する必要がなく、Spring Bootの設定ファイルだけで簡単に適用できるため、積極的に活用したいポイントです。

実際のシステムでは、バルク処理中に発生する可能性のある例外やロールバックにも対処しなければなりません。大量データを1つのトランザクションで処理すると、途中の例外で全体がロールバックされてしまうリスクがあるため、適切な粒度でトランザクションを分割する設計も重要な視点です。ログ出力やリトライ処理のような耐障害性を考えた設計も忘れてはいけません。以下は記事内容を再現したバルク挿入処理の例です。


@Transactional
public void optimizedBulkInsert(List<User> users) {
    for (int i = 0; i < users.size(); i++) {
        entityManager.persist(users.get(i));
        if (i % 100 == 0) {
            entityManager.flush();
            entityManager.clear();
        }
    }
}

このように、flushとclearを組み合わせたパフォーマンス最適化は、Spring Data JPAやHibernateを扱ううえで必須の知識といえます。大量データを扱う業務システムやデータ移行処理など、さまざまな場面で応用できる汎用性の高い技術であり、バルク更新、バルク削除、バルク挿入全体に応用できる考え方として覚えておくと非常に役立ちます。開発者が意識して最適化に取り組むことで、アプリケーション全体の応答速度や安定性が大きく改善され、ユーザー体験の向上にもつながります。

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

生徒

「flushとclearの意味がようやく理解できました!大量データを扱うときにどうして必要なのかもよくわかりました。」

先生

「その通りです。Springで大量データを扱うときは、エンティティをメモリに溜め込まないようにする工夫が大切なんです。」

生徒

「saveAllを使うだけじゃ不十分な理由も理解できました。便利だけど、自動で最適化されるわけじゃないんですね。」

先生

「そういうことです。EntityManagerを上手に使うことで、本来の性能を十分に引き出せますよ。」

生徒

「バルク更新や削除でPersistenceContextがズレるという話も、とても参考になりました。clearが本当に重要なんですね。」

先生

「そうなんです。整合性を保つためにはclearで一度状態をリセットすることが効果的なんです。」

生徒

「トランザクションの設計も大事だとわかりました。大量データはやっぱり甘く見たらダメですね。」

先生

「ええ、大量データの処理は安定性と速度のバランスが重要です。今回の知識を活かせば、より効率的なアプリケーションが作れますよ。」

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

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

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

Spring Bootで大量データを登録するときにsave()を繰り返すだけではなぜダメなのですか?

save()をループで繰り返すだけでは、すべてのエンティティがPersistenceContextに保持されてしまい、メモリ消費が増えパフォーマンスが大きく低下します。大量データにはflush()やclear()を使った工夫が必要です。

Springの学習を効率化したい方へ

この記事の内容をもっと深く知るには、以下の入門書が最適です。

Spring Framework超入門をAmazonで見る
カテゴリの一覧へ
新着記事
New1
Java
Javaのラムダ式で注意したい変数キャプチャの落とし穴とは?代入と変数名のベストプラクティス解説
更新記事
New2
Spring
Springの@GetMappingアノテーションの使い方を徹底解説!初心者でもわかるSpring Boot入門
更新記事
New3
Spring
SpringDataJPAのJPAクエリメソッド「EndingWith」の使い方を完全ガイド!初心者向け解説
更新記事
New4
Spring
SpringDataJPAのJPAクエリメソッド「StartingWith」の使い方を完全ガイド!初心者向け解説
更新記事
人気記事
No.1
Java&Spring記事人気No1
Spring
Spring BootとJavaの互換性一覧!3.5/3.4/3.3はJava 21・17に対応してる?
No.2
Java&Spring記事人気No2
Java
JavaのBooleanクラスの使い方を完全ガイド!初心者でもわかる真偽値の操作
No.3
Java&Spring記事人気No3
JSP
JSPの基本タグ一覧と使い方まとめ!実務で使えるタグを紹介
No.4
Java&Spring記事人気No4
Java
JavaのIOExceptionクラス徹底解説!初心者向けファイル入出力エラー対策ガイド
No.5
Java&Spring記事人気No5
Spring
SpringのBindingResultを完全ガイド!初心者でもわかる入力チェックとエラー処理
No.6
Java&Spring記事人気No6
JSP
JSPでif文・for文を使う方法!初心者でもわかるJavaとの違いと使い方
No.7
Java&Spring記事人気No7
Spring
SpringのModelクラスとaddAttributeメソッドの使い方を完全ガイド!初心者でも安心
No.8
Java&Spring記事人気No8
Spring
SpringDataJPAのJPAクエリメソッド「EndingWith」の使い方を完全ガイド!初心者向け解説