4.1.3.2. データを導出するバッチの作成(Chunkステップ)

Exampleアプリケーションを元に、既存データから計算を行い新たにデータを導出する Chunkステップ 方式のバッチを解説する。

作成する機能の概要
../../../../../../_images/overview.png
動作確認手順
  1. 登録対象テーブル(賞与テーブル)のデータを削除

    H2のコンソールから下記SQLを実行し、賞与テーブルのデータを削除する。

    TRUNCATE TABLE BONUS;
    
  2. 賞与計算バッチを実行

    コマンドプロンプトから賞与計算バッチを実行する。

$cd {nablarch-example-batch-eeシステムリポジトリ}
$mvn exec:java -Dexec.mainClass=nablarch.fw.batch.ee.Main ^
    -Dexec.args=bonus-calculate
  1. バッチ実行後の状態の確認

H2のコンソールから下記SQLを実行し、賞与情報が登録されたことを確認する。

SELECT * FROM BONUS;

4.1.3.2.1. データを導出する

既存データから新たにデータを導出するバッチの実装方法を以下の順に説明する。

  1. 入力データソースからデータを読み込む
  2. 業務ロジックを実行する
  3. 永続化処理を行う
  4. JOB設定ファイルを作成する

処理フローについては、 Chunkステップのバッチの処理フロー を参照。 責務配置については Chunkステップの責務配置 を参照。

バッチ処理は、 JSR352(外部サイト、英語) で規定されたインターフェースの実装に加えて、トランザクション制御などの共通的な処理を提供するリスナーによって構成する。 リスナーの詳細は バッチアプリケーションで使用するリスナー 及び リスナーの指定方法 を参照。

4.1.3.2.1.1. 入力データソースからデータを読み込む

計算に必要なデータを取得する処理を実装する。

  1. フォームの作成
  2. ItemReaderの作成
フォームの作成

Chunkステップでは、 ItemReaderItemProcessor とのデータ連携にフォームを使用する。

EmployeeForm.java
public class EmployeeForm {

    //一部のみ抜粋

    /** 社員ID */
    private Long employeeId;

    /**
     * 社員IDを返します。
     *
     * @return 社員ID
     */
    public Long getEmployeeId() {
        return employeeId;
    }

    /**
     * 社員IDを設定します。
     *
     * @param employeeId 社員ID
     */
    public void setEmployeeId(Long employeeId) {
        this.employeeId = employeeId;
    }
}
ItemReaderの作成

AbstractItemReader を継承し、データの読み込みを行う。

インタフェース名 責務
ItemReader

データの読み込みを行う。

空実装を提供する AbstractItemReader を継承する。

  • ItemReader#open
  • ItemReader#readItem
  • ItemReader#close
EmployeeSearchReader.java
@Dependent
@Named
public class EmployeeSearchReader extends AbstractItemReader {

    /** 社員情報のリスト */
    private DeferredEntityList<EmployeeForm> list;

    /** 社員情報を保持するイテレータ */
    private Iterator<EmployeeForm> iterator;

    @Override
    public void open(Serializable checkpoint) throws Exception {
        list = (DeferredEntityList<EmployeeForm>) UniversalDao.defer()
                .findAllBySqlFile(EmployeeForm.class, "SELECT_EMPLOYEE");
        iterator = list.iterator();
    }

    @Override
    public Object readItem() {
        if (iterator.hasNext()) {
            return iterator.next();
        }
        return null;
    }

    @Override
    public void close() throws Exception {
        list.close();
    }
}
EmployeeForm.sql
SELECT_EMPLOYEE=
SELECT
    EMPLOYEE.EMPLOYEE_ID,
    EMPLOYEE.FULL_NAME,
    EMPLOYEE.BASIC_SALARY,
    EMPLOYEE.GRADE_CODE,
    GRADE.BONUS_MAGNIFICATION,
    GRADE.FIXED_BONUS
FROM
    EMPLOYEE
INNER JOIN GRADE ON EMPLOYEE.GRADE_CODE = GRADE.GRADE_CODE
この実装のポイント

4.1.3.2.1.2. 業務ロジックを実行する

賞与の計算等の業務ロジックを実装する。

ItemProcessorの作成

ItemProcessor を実装し、 業務ロジックを行う(永続化処理は ItemWriter の責務であるため実施しない)。

インタフェース名 責務
ItemProcessor

一行分のデータに対する業務処理を行う。

  • ItemProcessor#processItem
BonusCalculateProcessor.java
@Dependent
@Named
public class BonusCalculateProcessor implements ItemProcessor {

    @Override
    public Object processItem(Object item) {

        EmployeeForm form = (EmployeeForm) item;
        Bonus bonus = new Bonus();
        bonus.setEmployeeId(form.getEmployeeId());
        bonus.setPayments(calculateBonus(form));

        return bonus;
    }

    /**
     * 社員情報をもとに賞与計算を行う。
     *
     * @param form 社員情報Form
     * @return 賞与
     */
    private static Long calculateBonus(EmployeeForm form) {
        if (form.getFixedBonus() == null) {
            return form.getBasicSalary() * form.getBonusMagnification() / 100;
        } else {
            return form.getFixedBonus();
        }
    }
}
この実装のポイント

4.1.3.2.1.3. 永続化処理を行う

DB更新等の、永続化処理を実装する。

ItemWriterの作成

ItemWriter を実装し、データの永続化を行う。

インタフェース名 責務
ItemWriter

データを永続化する。

  • ItemWriter#writeItems
BonusWriter.java
@Dependent
@Named
public class BonusWriter extends AbstractItemWriter {

    @Override
    public void writeItems(List<Object> items) {
        UniversalDao.batchInsert(items);
    }
}
この実装のポイント
  • UniversalDao#batchInsert を使用してエンティティのリストを一括登録する。
  • writeItems メソッド実行後にトランザクションがコミットされ、新たなトランザクションが開始される。
  • writeItems メソッド実行後、バッチ処理が readItem メソッド実行から繰り返される。

4.1.3.2.1.4. JOB設定ファイルを作成する

JOBの実行設定を記載したファイルを作成する。

bonus-calculate.xml
<job id="bonus-calculate" xmlns="http://xmlns.jcp.org/xml/ns/javaee" version="1.0">
  <listeners>
    <listener ref="nablarchJobListenerExecutor" />
  </listeners>

  <step id="step1">
    <listeners>
      <listener ref="nablarchStepListenerExecutor" />
      <listener ref="nablarchItemWriteListenerExecutor" />
    </listeners>

    <chunk item-count="1000">
      <reader ref="employeeSearchReader" />
      <processor ref="bonusCalculateProcessor" />
      <writer ref="bonusWriter" />
    </chunk>
  </step>
</job>
この実装のポイント
  • ジョブ定義ファイルは /src/main/resources/META-INF/batch-jobs/ 配下に配置する。
  • job 要素 の id 属性で、ジョブ名称を指定する。
  • chunk 要素の item-count 属性で writeItems 一回当たりで処理する件数を設定する。
  • 設定ファイルの詳細な記述方法は JSR352 Specificationを参照(外部サイト、英語) を参照。