しおしお

IntelliJのあれやこれや

JSR352-Batch Applicationを試してみた(BatchletでDBアクセス-JPA編)

JSR352-Batch Applicationを試してみた(Batchlet編) - しおしお(´・ω・`)の続編です。

今回は、Batchletでデータベースにアクセスしてみようかなと。データベースへのアクセス方法は、JPA使ってもいいし、素のJDBCオープンソースのライブラリを使ってもいいでしょう。

今回は、JPAを使ってみます。JPAを使った場合、Batchletの実装ではJTAトランザクションが開始されていないので、Batchretで新しいトランザクションを開始して上げる必要があります。

※Bachletの処理は下の流れで行われると仕様に書かれているので、Batchletでデータベースアクセスするのってあんまり想定されていないんかなと思ったり。でも、ガツンと一発で処理したいときはBatchletでやりたいしなぁと

11.4 Regular Batchlet Processsing

  1. <Create StepContext>
  2. <Store step level properties in StepContext>
  3. <->[StepListener.beforeStep...] // thread A
  4. <->Batchlet.process // thread A
  5. // if stop issued:
  6. <->[Batchlet.stop] // thread B, StepContext is available
  7. <->[StepListener.afterStep...] // thread A
  8. <Store StepContext persistent area>
  9. <Destroy StepContext>

さっそく実装例を簡単に。。。

Batchlet実装

ジョブ定義で指定した数分のデータをJPAを使って登録しているだけのBatchletです。登録件数のフィールドがStringになっているのは、参照実装がBatchPropertyで数値を使えないので・・・。(JBeretはString以外の型も使いそうなのはサポートしてくれているのですがね。)

package siosio.batchlet;

import javax.batch.api.AbstractBatchlet;
import javax.batch.api.BatchProperty;
import javax.enterprise.context.Dependent;
import javax.inject.Inject;
import javax.inject.Named;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.transaction.Transactional;
import javax.transaction.Transactional.TxType;

import siosio.entity.UserEntity;

@Dependent
@Named
@Transactional(TxType.REQUIRES_NEW)
public class DbAccessBatchlet extends AbstractBatchlet {

    @PersistenceContext(unitName = "batch")
    EntityManager em;

    @Inject
    @BatchProperty
    String count;

    @Override
    public String process() throws Exception {
        final int insertCount = Integer.parseInt(count);

        for (int i = 0; i < insertCount; i++) {
            em.persist(new UserEntity("name_" + (i + 1)));
        }

        return "SUCCESS";
    }
}

Entityの実装

IDと属性を1つだけ持ったEntityを作っています。とりあえず、動かすことが目的なのでこの程度で十分でしょうと。

package siosio.entity;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.NamedQuery;
import javax.persistence.Table;

@Entity
@Table(name = "users")
public class UserEntity {

    private Long id;

    private String name;

    public UserEntity() {
    }

    public UserEntity(String name) {
        this.name = name;
    }

    @Id
    @GeneratedValue
    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

ジョブ定義ファイル

上で作ったBatchletをステップに指定しています。countプロパティに50を指定しているので、50レコードが登録されます。

<job id="db-access-job" xmlns="http://xmlns.jcp.org/xml/ns/javaee" version="1.0">
  <step id="clear-users">
    <batchlet ref="dbAccessBatchlet">
      <properties>
        <property name="count" value="50" />
      </properties>
    </batchlet>
  </step>
</job>

persistence.xml

特にこれといって何もありません。。。

<?xml version="1.0" encoding="UTF-8"?>
<persistence xmlns="http://xmlns.jcp.org/xml/ns/persistence" version="2.1">

  <persistence-unit name="batch" transaction-type="JTA">
    <provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
    <jta-data-source>jdbc/jbatch</jta-data-source>
    <exclude-unlisted-classes>false</exclude-unlisted-classes>
    <properties>
      <property name="javax.persistence.schema-generation.database.action" value="create" />
      <property name="eclipselink.logging.level" value="fine" />
    </properties>
  </persistence-unit>

</persistence>

実行結果の確認を・・・

分かりづらいけど、テーブルに50レコード入ったしちゃんと動いたんだろな感がある。

f:id:sioiri:20150607151221p:plain

ソースコード全量はこちら→siosio/jbatch-sample · GitHub


おわり。