2012年5月23日水曜日

[java]springbatchのジョブ設定


適当なジョブ設定ファイルのサンプル。

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:p="http://www.springframework.org/schema/p"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/batch http://www.springframework.org/schema/batch/spring-batch-2.1.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">


    <!-- enables the functionality of JobOperator.startNextInstance(jobName) -->
    <bean id="jobParametersIncrementer"
          class="org.springframework.batch.core.launch.support.RunIdIncrementer"/>


    <job id="accountBkJob" xmlns="http://www.springframework.org/schema/batch" incrementer="jobParametersIncrementer">
        <step id="accountBk" parent="accountBkStep"/>
    </job>


    <step id="accountBkStep" xmlns="http://www.springframework.org/schema/batch">
        <tasklet>
            <chunk reader="accountBkSource" writer="accountBkWriter"
            commit-interval="${job.commit.interval}"/>
        </tasklet>
    </step>


    <bean id="accountBkSource" class="org.springframework.batch.item.database.JdbcPagingItemReader">
        <property name="dataSource" ref="dataSource"/>
        <property name="rowMapper">
            <bean class="sample.domain.internal.AccountBkMapper"/>
        </property>
        <property name="queryProvider">
            <bean class="org.springframework.batch.item.database.support.SqlPagingQueryProviderFactoryBean">
                <property name="dataSource" ref="dataSource"/>
                <property name="fromClause" value="from proto_spring_batch.account "/>
                <property name="selectClause" value="select proto_spring_batch.account.* "/>
                <property name="sortKey" value="ID"/>
            </bean>
        </property>
        <property name="pageSize" value="10"/>
    </bean>


    <!--<bean id="accountBkSource" class="org.springframework.batch.item.database.JdbcCursorItemReader">-->
        <!--<property name="dataSource" ref="dataSource"/>-->
        <!--<property name="rowMapper">-->
            <!--<bean class="sample.domain.internal.AccountBkMapper"/>-->
        <!--</property>-->
        <!--<property name="sql">-->
            <!--<value>-->
                <!--select proto_spring_batch.account.* from proto_spring_batch.account order by-->
                <!--proto_spring_batch.account.id asc-->
            <!--</value>-->
        <!--</property>-->
        <!--<property name="verifyCursorPosition" value="${batch.verify.cursor.position}"/>-->
    <!--</bean>-->


    <bean id="accountBkWriter" class="sample.domain.internal.JdbcAccountBkDao">
        <property name="dataSource" ref="dataSource"/>
    </bean>


    <bean id="accountBkProperties" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
        <property name="properties">
            <value>
                job.commit.interval=5
            </value>
        </property>
        <property name="systemPropertiesModeName" value="SYSTEM_PROPERTIES_MODE_OVERRIDE"/>
        <property name="ignoreUnresolvablePlaceholders" value="true"/>
        <property name="order" value="1"/>
    </bean>


</beans>

これはDBからページング機能を利用してデータを読み込んで、DBに出力するジョブの設定。
コメントアウトでカーソル機能版。
ちなみにこの設定では、1ページ10レコード読み込んで5件ごとにコミット。
1ページで2回コミットするわけだけど、1回目のコミット後に例外発生して処理が失敗しても
1ページ目の続きからリランしてくれる。
なかなか便利。
MySQLな人には当たり前だけどMyISAMだとロールバックできないからテーブルのtype=InnoDBを忘れずに。
show tables status; とかで見えたはず。

具体的には、同じテーブル構成のaccountテーブルからaccount_bkテーブルにデータを少しずつコピーしていくだけ。
SQLクエリで一発だけど理解するために。
whereClauseを外してるけど、Where句を使用するときには指定する。
Where句のパラメータを動的に渡したい時はどうやるんかな…。

MapperとかItemWritterとかはたいして特別なことはせずにサンプルを見ながら適当に実装。

ItemWritterとか。
package sample.domain.internal;

import org.springframework.batch.item.ItemWriter;
import org.springframework.jdbc.core.namedparam.BeanPropertySqlParameterSource;
import org.springframework.jdbc.core.simple.SimpleJdbcDaoSupport;
import sample.domain.internal.model.Account;

import java.util.List;

/**
 * Created with IntelliJ IDEA.
 * User: hoge
 * Date: 12/05/23
 * Time: 18:58
 * To change this template use File | Settings | File Templates.
 */
public class JdbcAccountBkDao extends SimpleJdbcDaoSupport implements ItemWriter<Account> {

    public static final String INSERT_ACCOUNT_BK =
            "INSERT into proto_spring_batch.account_bk (id, account_id, account_name, insert_date, update_date, delete_flg)" +
                    " values (:id, :accountId, :accountName, :insertDate, :updateDate, :deleteFlg) ON DUPLICATE KEY UPDATE " +
                    "account_id = :accountId, account_name = :accountName, update_date = :updateDate";

    public void write(List<? extends Account> accounts) throws Exception {
        for (Account account : accounts) {
            getSimpleJdbcTemplate().update(INSERT_ACCOUNT_BK, new BeanPropertySqlParameterSource(account));
        }
        if (accounts != null) {
            throw new Exception("任意で発生させたエラーだよ");
        }
    }
}


Mapperとか。
package sample.domain.internal;

import org.springframework.jdbc.core.simple.ParameterizedRowMapper;
import sample.domain.internal.model.Account;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Date;

/**
 * Created with IntelliJ IDEA.
 * User: hoge
 * Date: 12/05/23
 * Time: 18:48
 * To change this template use File | Settings | File Templates.
 */
public class AccountBkMapper implements ParameterizedRowMapper<Account> {
    public Account mapRow(ResultSet rs, int rowNum) throws SQLException {
        Account account = new Account();
        account.setId(rs.getLong(1));
        account.setAccountId(rs.getString(2));
        account.setAccountName(rs.getString(3));
        account.setInsertDate(new Date());
        account.setUpdateDate(new Date());
        account.setDeleteFlg(false);
        return account;
    }
}

そんなもんかな。

0 件のコメント:

コメントを投稿