本ページはプロモーションが含まれています

Java入門

【2026年版】Javaバッチ処理の実装方法3選と設計のコツ

トム

・都内自社開発企業勤務/Javaバックエンドエンジニア
/Java歴10年以上 ・首都圏在住30代
・資格:基本情報技術者/応用情報技術者/Java Silver/Python3エンジニア認定基礎 詳細なプロフィール

Javaのバッチ処理は、mainメソッド・Spring Batch・Quartzの3パターンで実装でき、それぞれ向き不向きが異なります。

数百件程度の単純な処理ならmainメソッドで十分ですが、リトライやジョブ管理が必要な本番運用ではSpring Batchを選ぶのが安全です。

この見極めを含め、3つの実装方法と、安定稼働に欠かせない5つの設計ポイント(リトライ・ログ管理・パフォーマンス最適化・トランザクション管理・冪等性確保)をサンプルコード付きでまとめました。

金融機関の大規模システムからスタートアップのWebサービスまで、複数のプロジェクトでJavaバッチ処理を開発してきた経験にもとづいています。

この記事でわかること

  • Javaバッチ処理の3つの実装方法(mainメソッド・Spring Batch・Quartz)の使い分け
  • 安定稼働に欠かせない5つの設計ポイント(リトライ・ログ管理・パフォーマンス・トランザクション・冪等性)
  • ファイル・DB・API連携それぞれのサンプルコード

バッチ処理とは?

バッチ処理とは何かをリアルタイム処理と対比して示す図解

Javaでバッチ処理を学ぶ前に、まずは「バッチ処理」そのものについて理解を深めましょう。

バッチ処理とは、ある程度の量のデータを一かたまり(バッチ)にして、一括で処理する方式を指します。

身近な例でいうと、銀行の夜間利息計算や、企業の給与計算、ECサイトの売上集計などがバッチ処理にあたります。

ユーザーからのリクエストのたびに処理するのではなく、決められた時間にまとめて実行するのが特徴です。

バッチ処理とリアルタイム処理の違い

バッチ処理とよく比較されるのが「リアルタイム処理」です。この2つの違いを理解すると、バッチ処理の役割がより明確になります。

項目バッチ処理リアルタイム処理
処理のタイミング事前に決められたスケジュール(夜間など)ユーザーのリクエストに応じて即時
データの量大量少量(1件〜)
処理時間ある程度の時間がかかる非常に短い(ミリ秒単位)
主な用途データ集計、バックアップ、給与計算などオンライン取引、座席予約、SNSの投稿など
システムへの負荷実行時に集中して高くなる常に一定の負荷がかかる

簡単に言えば、「ためて一気に片付ける」のがバッチ処理で、「その都度すぐに片付ける」のがリアルタイム処理とイメージすると分かりやすいでしょう。

どちらが良いというわけではなく、用途に応じて使い分けるのが重要です。

バッチ処理とバッチファイル(.bat)の違い

「バッチ処理」と名前が似ている言葉に「バッチファイル」がありますが、この2つは別の概念です。

バッチファイルとは、Windows環境で使われる拡張子.batのファイルのことで、複数のコマンドを上から順に実行するための仕組みを指します。

一方、バッチ処理は「大量のデータを一括で処理する方式」というより広い概念です。

バッチファイルはその実現手段の一つにすぎず、Javaのバッチ処理はバッチファイルに依存しません。

cronやタスクスケジューラ、あるいはSpring Batchのようなフレームワークと組み合わせることで、Javaプログラム単体でバッチ処理を実現できます。

Javaでバッチ処理を行うメリット

世の中にはさまざまなプログラミング言語がありますが、その中でもJavaでバッチ処理を開発するメリットは主に3つあります。

ポイント

  1. 豊富なライブラリとフレームワーク:Javaには、Spring Batchをはじめとする、バッチ処理開発を力強くサポートしてくれるフレームワークが多数存在します。これらのフレームワークが提供するエコシステムを活用することで、エラー処理やリトライ、大量データ処理といった複雑な要件を、効率よく安全に実装できます。
  2. プラットフォームへの非依存性:Javaは「Write Once, Run Anywhere(一度書けば、どこでも動く)」という思想の通り、OSに依存しません。Windowsサーバーで開発したバッチ処理を、本番環境のLinuxサーバーで動かすといった運用が容易なのは、大きな魅力です。
  3. 既存の資産と人材の活用:多くの企業システムがJavaで開発されているため、既存のビジネスロジックやデータアクセス層のコードを再利用しやすいメリットがあります。また、Javaエンジニアは市場に多いため、開発や保守の人材を確保しやすいのも大きな利点です。

Javaバッチ処理の開発方法|3つの基本アプローチ

Javaバッチ処理を実装する3つの基本的なアプローチを示す図解

それでは、具体的にJavaでバッチ処理を実装する方法を見ていきましょう。基本的なアプローチは大きく分けて3つあります。

mainメソッドを使った単純な処理

最もシンプルな方法は、mainメソッドを持つクラスを作成し、その中に処理を記述する方法です。

特別なライブラリは不要で、Javaの基本的な知識だけで実装できます。

public class SimpleBatch {
    public static void main(String[] args) {
        System.out.println("バッチ処理を開始します。");

        // ここに実行したい処理を記述する
        // 例: ファイルの読み込み、データベースの更新など
        try {
            // 5秒かかる処理をシミュレート
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println("バッチ処理が正常に終了しました。");
    }
}

このJavaプログラムをコンパイルし、コマンドラインから実行すれば、立派なバッチ処理の完成です。

引数(String[] args)を使えば、実行時に処理内容を切り替えることもできます。

スケジューラー(cronやタスクスケジューラ)の利用

mainメソッドで作ったプログラムは、手動で実行する必要がありました。これを自動化するのがスケジューラーです。

OSに標準で搭載されている機能で、指定した時間にプログラムを自動で実行してくれます。

  • Linux/macOSの場合: cron
  • Windowsの場合: タスクスケジューラ

例えば、Linuxのcronを使って毎日深夜2時に上記のJavaプログラムを実行するには、以下のように設定します。

# crontab -e で編集
0 2 * * * /usr/bin/java -cp /path/to/your/classes com.example.SimpleBatch

OSのスケジューラーと組み合わせることで、定期的なJavaバッチ処理の実行が実現します。

複数ファイルや大量データの処理方法

数百万件のデータや、大量のファイルを一度に処理する場合、何も考えずに実装するとメモリ不足を引き起こします。

メモリ不足を避けるには、一度にすべてのデータをメモリに読み込むのではなく、少しずつ読み込んで処理する「ストリーム処理」が基本です。

JavaではBufferedReaderInputStreamを使うことで、ファイルやネットワークからのデータを一行ずつ、あるいは少しずつ読み込めます。

データベースから大量のデータを取得する場合も同様に、一度に全件取得するのではなく、カーソルを使って一件ずつ処理する、あるいはページング処理で一定件数ずつ取得するといった工夫が求められます。

あわせて読む

Javaバッチ処理の開発で使うフレームワーク比較

Javaバッチ処理で使われる主要ライブラリ・フレームワークの比較を示す図解

mainメソッドだけのシンプルな実装は手軽ですが、エラーハンドリングやリトライ、処理の再実行などを自前で作り込むのは大変です。

そこで、実務ではバッチ処理に特化したフレームワークを利用するのが一般的です。

あわせて読む

Spring Batchの特徴と導入方法

Spring Batchは、Javaのバッチ処理フレームワークにおけるデファクトスタンダード(事実上の標準)です。

エンタープライズシステムで求められる複雑な要件に対応するための、さまざまな機能を提供しています。

主な特徴:

特徴

  • チャンクモデル: 一定件数(チャンク)ごとにデータを読み込み、処理し、書き込むモデル。大量データ処理のパフォーマンスとメモリ効率に優れています。
  • 豊富なコンポーネント: ファイルやデータベース、JMSキューなど、さまざまなデータソースに対応した読み込み・書き込み用コンポーネントが標準で用意されています。
  • リトライとスキップ: 処理中に一時的なエラーが発生した場合に自動でリトライしたり、特定のエラーが発生したデータをスキップして処理を継続したりする機能があります。
  • ジョブ管理: 処理の実行状態(成功、失敗など)をデータベースで管理するため、どこまで処理が進んだか、どのデータでエラーになったかの追跡が容易です。

Spring Bootを利用すれば、build.gradlepom.xmlに以下の依存関係を追加するだけで、簡単にSpring Batchを導入できます。

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-batch</artifactId>
</dependency>

2026年8月時点の最新はSpring Batch 5.2系(5.2.7、Spring Boot 3.x)およびSpring Batch 6.0系(6.0.4、Spring Boot 4.x)です。

本格的なJavaバッチ処理を開発するなら、まず最初に検討すべきフレームワークです。

あわせて読む

Quartzによるジョブ管理

Quartzは、ジョブのスケジューリングに特化したライブラリです(2026年8月時点の最新は2.5系)。

「毎週月曜の朝9時に実行」「15分おきに実行」といった、cronよりも柔軟で複雑なスケジュールをJavaコードで管理できます。

Spring Batch自体にはスケジューリング機能がないため、Spring Batchで処理内容を定義し、Quartzで実行タイミングを制御するという組み合わせは非常によく使われます。

あわせて読む
あわせて読む

シンプルなバッチ処理に便利なツール

Spring Batchは高機能ですが、設定がやや複雑で、ごく簡単な処理には大げさな場合もあります。

数分で終わるような単純なデータ連携処理などであれば、java.util.concurrent.ScheduledExecutorService を使って、Javaアプリケーション内で簡易的なスケジューリングを実装する方法も考えられます。

外部ライブラリを追加したくない、小規模なツールを作成したい、といった場合に検討してください。

jBatch(JSR-352):Java標準のバッチ仕様

jBatch(JSR-352)は、Java EE 7で標準化されたバッチ処理の仕様です。

Spring Batchのアーキテクチャを参考に策定されており、Job・Step・Chunk・Batchletといった基本モデルはSpring Batchと似た構造を持っています。

2026年8月時点でも、Jakarta EE 11に対応したJakarta Batch 2.1が最新です。

Spring Bootプロジェクトであればspring-boot-starter-batchを使うのが自然ですが、Jakarta EEアプリケーションサーバー(WildFly、Open Libertyなど)上で動作させる場合はjBatchが選択肢に入ります。

Javaバッチ処理の設計ポイント5つ

Javaバッチ処理を安定稼働させるための5つの設計ポイントを示す図解

安定して動作するバッチ処理を構築するには、実装だけでなく「設計」が非常に重要です。

私がこれまで関わったプロジェクトで共通して感じたのは、バッチ処理の品質は設計で8割決まるということです。

実装自体はシンプルでも、リトライ戦略やログ設計を怠ると、障害時の対応コストが跳ね上がります。ここでは、特に意識すべき5つのポイントを紹介します。

リトライ・エラーハンドリングの考え方

バッチ処理は夜間など、人の目が届かない時間帯に動くことが多いです。

そのため、エラーが発生した際に処理を安全に停止し、原因を記録し、可能であれば自動で復旧する仕組みが不可欠です。

  • リトライ: データベース接続のタイムアウトなど、一時的な問題で発生したエラーは、少し時間をおいて再試行(リトライ)すれば成功する可能性があります。
  • エラーハンドリング: リトライしても解消しないエラーや、データの不整合といった致命的な問題が発生した場合は、処理を中断します。その際、エラー内容、発生箇所、処理中のデータをログに詳しく記録し、開発者が原因を特定できるようにしておく必要があります。
  • 再実行性: 失敗した処理を、途中から再実行できる設計(リラン可能)にしておくと、運用負荷を大きく下げられます。Spring Batchは、このあたりの仕組みをうまくサポートしています。
あわせて読む

ログ管理と監視の仕組み

「バッチが正常に動いているか?」を把握するためのログ設計も重要です。最低限、以下の情報はログに出力しましょう。

  • 処理の開始・終了時刻
  • 処理したデータの件数(読み込み件数、書き込み件数)
  • エラーが発生した場合は、その内容とスタックトレース
  • 主要な処理の経過時間

これらのログはファイルに出力するだけでなく、DatadogMackerelといった監視ツールで収集・監視するのが望ましいです。

異常の早期検知や、処理時間の悪化といったパフォーマンスの問題に、より早く気づけるようになります。

パフォーマンス最適化のコツ

大量のデータを扱うバッチ処理では、パフォーマンスが問題になりがちです。処理時間が想定より長引くと、次の日のオンライン業務に影響を及ぼします。

私自身、Spring Batchのchunk sizeを1000に設定した本番バッチでOOM(OutOfMemoryError)を発生させた経験があります。

原因調査に2時間かかりましたが、chunk sizeを100に変更するだけで解決しました。

この経験から「chunk sizeは小さく始めて、パフォーマンスを見ながら徐々に上げる」のが鉄則だと学びました。

  • ボトルネックの特定: 処理が遅い場合、原因はCPU、メモリ、ディスクI/O、ネットワークのどこにあるのかを特定します。
  • データベースアクセス: 大量データをループ内で1件ずつINSERTUPDATEするのは非常に非効率です。バルクインサート(一括登録)を利用しましょう。また、SELECT文のパフォーマンスが悪い場合は、インデックスが適切に設定されているか確認しましょう。
  • メモリ使用量: 大量のデータをオブジェクトとしてメモリに保持し続けないように注意します。不要になったオブジェクトは速やかに参照を解除し、ガベージコレクションの対象になるようにしましょう。
  • 並列処理: 互いに依存しない処理であれば、複数のスレッドで並列実行することで、全体の処理時間を短縮できます。Spring Batchには、パーティショニングという仕組みで並列処理を簡単にする機能があります。
あわせて読む

トランザクション管理とコミット戦略

バッチ処理では、大量データを一度にコミットすると障害時のロールバック範囲が広がり、復旧に時間がかかります。

そのため、チャンク単位のコミットが基本戦略です。

Spring Batchではcommit-interval(例: 1000件)を設定することで、一定件数ごとにコミットを実行します。

コミット間隔が小さすぎるとDB負荷が増え、大きすぎると障害時の再処理量が増えるため、実務では500〜1000件が一般的な目安です。

なお、Spring Batchと組み合わせて@Transactionalを使う場合は注意が必要です。

同一クラス内のメソッド呼び出しではトランザクションが効きません(Springのプロキシベースの制約)。

私は本番環境でデータ不整合が発生して初めてこの問題に気づきました。バッチのサービス層は必ずクラスを分割し、外部から呼び出す設計にしましょう。

冪等性の確保(再実行しても安全な設計)

冪等性(べきとうせい)とは、同じ処理を何度実行しても結果が変わらない性質のことです。

バッチ処理では障害時の再実行や重複実行が避けられないため、冪等な設計が求められます。

具体的な実現方法としては、INSERTの代わりにUPSERTを使う、処理済みフラグや処理日時カラムで二重処理を防ぐ、といった手法があります。

UPSERTの構文はDB製品によって異なり、MySQLではINSERT ... ON DUPLICATE KEY UPDATE、PostgreSQLではINSERT ... ON CONFLICTを使います。

Spring BatchではJobInstanceJobExecutionの仕組みで再実行を制御できます。

あわせて読む

実践例:Javaバッチ処理のサンプルコード3選

Javaバッチ処理のサンプルコード3選を示す図解

ここでは、よくある3つのケースについて、簡単なサンプルコードを交えながら実装イメージを紹介します。

ファイル読み込みと書き込み

CSVファイルを1行ずつ読み込み、特定の条件(例: 2列目の値が "TOKYO")に一致する行だけを別のファイルに書き出すバッチ処理です。

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.nio.file.Files;
import java.nio.file.Paths;

public class FileBatchExample {
    public static void main(String[] args) {
        String inputFile = "input.csv";
        String outputFile = "output.csv";

        try (BufferedReader reader = Files.newBufferedReader(Paths.get(inputFile));
             BufferedWriter writer = Files.newBufferedWriter(Paths.get(outputFile))) {

            String line;
            while ((line = reader.readLine()) != null) {
                String[] columns = line.split(",");
                if (columns.length >= 2 && "TOKYO".equals(columns[1])) {
                    writer.write(line);
                    writer.newLine();
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

データベース連携

JDBCを使い、usersテーブルから未処理のユーザー(status = 0)を取得し、処理済み(status = 1)に更新する例です。

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;

public class DbBatchExample {
    public static void main(String[] args) {
        String url = "jdbc:mysql://localhost:3306/mydb";
        String user = "user";
        String password = "password";

        String selectSql = "SELECT id FROM users WHERE status = 0";
        String updateSql = "UPDATE users SET status = 1 WHERE id = ?";

        try (Connection conn = DriverManager.getConnection(url, user, password);
             PreparedStatement selectStmt = conn.prepareStatement(selectSql);
             PreparedStatement updateStmt = conn.prepareStatement(updateSql)) {
            
            conn.setAutoCommit(false); // トランザクション開始
            ResultSet rs = selectStmt.executeQuery();

            while (rs.next()) {
                int id = rs.getInt("id");
                // 何らかの処理...
                updateStmt.setInt(1, id);
                updateStmt.addBatch();
            }
            updateStmt.executeBatch(); // バッチ更新
            conn.commit(); // トランザクション確定

        } catch (Exception e) {
            // エラー発生時はロールバックする(コードは省略)
            e.printStackTrace();
        }
    }
}

APIを利用したデータ取得と保存

外部のAPIからJSON形式で天気情報を取得し、その結果をファイルに保存するバッチ処理です。

Java 11から標準搭載されたHttpClientを利用しています(Java 21/25 LTSでも利用可能)。

import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.nio.file.Files;
import java.nio.file.Paths;

public class ApiBatchExample {
    public static void main(String[] args) {
        HttpClient client = HttpClient.newHttpClient();
        HttpRequest request = HttpRequest.newBuilder()
                .uri(URI.create("https://api.weather.example.com/tokyo"))
                .build();

        try {
            HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
            String jsonData = response.body();
            
            // 取得したJSONデータをファイルに保存
            Files.writeString(Paths.get("weather.json"), jsonData);

        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
あわせて読む

Javaバッチ処理のよくある質問(FAQ)

Q. Javaのバッチ処理とリアルタイム処理はどう使い分ける?

大量データの一括処理(売上集計・データ移行・バックアップなど)にはバッチ処理、ユーザーの操作に即座に応答する必要がある処理(オンライン取引・チャットなど)にはリアルタイム処理が適しています。処理の即時性よりもスループットを優先する場面ではバッチ処理を選びましょう。

Q. Spring Batchは小規模プロジェクトでも使うべき?

数百件程度のデータ処理や、数分で終わる単純な処理であれば、mainメソッド+ScheduledExecutorServiceで十分です。一方、リトライ・スキップ・ジョブ管理・再実行制御が必要な場合は、規模に関わらずSpring Batchを導入します。

Q. バッチ処理が失敗したときの対処法は?

まずログでエラー箇所と原因を特定し、一時的な障害(DB接続タイムアウトなど)であればリトライで復旧します。データ不整合が原因の場合は、該当データを修正した上で冪等性が担保された設計であれば安全に再実行できます。Spring BatchのJobExecutionを使えば、失敗したステップから再開することも可能です。

Q. Javaのバッチ処理とバッチファイルは同じですか?

いいえ、別の概念です。バッチファイルはWindows環境で使われる拡張子.batのコマンド実行ファイルを指し、バッチ処理はデータを一括処理する方式そのものを指します。バッチファイルはバッチ処理を実現する手段の一つにすぎません。

Q. Javaバッチ処理のフレームワークはどれを選べばいいですか?

エンタープライズ用途で複雑な要件があれば、デファクトスタンダードのSpring Batchが第一候補です。Jakarta EEアプリケーションサーバー上で動かす場合はjBatch、cronより柔軟なスケジュール管理が必要な場合はQuartzを併用します。

Q. Javaバッチ処理でメモリ不足を防ぐには?

一度にすべてのデータをメモリへ読み込まず、BufferedReaderやページング処理で少しずつデータを読み込むストリーム処理が基本です。データベースから取得する場合も、カーソルや一定件数ずつのページング取得が有効です。

まとめ

Javaのバッチ処理は、規模と要件に応じてmainメソッド・Spring Batch・Quartzを使い分け、リトライ・ログ管理・パフォーマンス・トランザクション・冪等性の5つを設計段階で押さえておくことで安定稼働します。

バッチ処理は、Webアプリケーションのように華やかではありませんが、ビジネスシステムを裏で支える非常に重要な技術です。

安定したバッチ処理を構築できるスキルは、Javaエンジニアとして大きな強みになります。

Javaバッチ処理の学習ロードマップ

これからJavaのバッチ処理を本格的に学びたい方は、以下のステップで進めるのがおすすめです。

  1. Javaの基本をマスターする: ファイルI/O、JDBC、例外処理など、基本的なAPIをしっかり理解します。
  2. mainメソッドで簡単な処理を作る: まずはライブラリに頼らず、小さなバッチを自分で作ってみましょう。
  3. Spring Batchを学ぶ: 公式ドキュメントや入門書を参考に、Spring Batchの基本(Job, Step, ItemReader, ItemWriter)を学び、チュートリアルを動かしてみます。
  4. 設計と運用の知識を深める: エラーハンドリング、ログ設計、監視、パフォーマンスチューニングなど、本記事で紹介した設計のポイントを意識して、より実践的なバッチ処理の構築を目指します。

まずは、Spring BootとSpring Batchを使って、簡単なCSVファイルとデータベースを連携させるバッチ処理を作成してみることをお勧めします。

実際に作ってみることで、フレームワークの便利さや、設計で考慮すべき点がより具体的に理解できるはずです。

  • この記事を書いた人
  • 最新記事

トム

・都内自社開発企業勤務/Javaバックエンドエンジニア
/Java歴10年以上 ・首都圏在住30代
・資格:基本情報技術者/応用情報技術者/Java Silver/Python3エンジニア認定基礎 詳細なプロフィール

-Java入門