99.Spring BatchのTips
概要
Spring BatchのTipsを記述していきます。
使用前に他の概要などの記事を読んでおくことをお勧めします。
ここでは詳しい説明は省きますので、読んでいなかった場合、使用方法が正確に伝わらないかもしれません。
チャンク編
FlatFileItemReaderで固定文字数のデータを読み込む方法
固定文字数のデータ(例:0000005 taro 22)を読み込む方法は、以下のとおりです。
FlatFileItemReaderのlineTokenizerとして以下のクラスを指定します。
【固定文字列を読み込むためのtokenizerの例】
<bean id="fixedLengthLineTokenizer"
class="org.springframework.batch.item.file.transform.FixedLengthTokenizer">
<property name="names" value="num,name,age" />
<property name="columns" value="1-7, 7-18, 19-21" />
</bean>
FlatFileItemWriterでprintfと同様の変換をする方法
<bean id="fileItemWriter" class="org.springframework.batch.item.file.FlatFileItemWriter">
<property name="resource" value="file:c:/test.txt" />
<property name="lineAggregator">
<bean class="org.springframework.batch.item.file.transform.FormatterLineAggregator">
<property name="fieldExtractor">
<bean class="org.springframework.batch.item.file.transform.BeanWrapperFieldExtractor" >
<property name="names" value="name,num" />
</bean>
</property>
<property name="format" value="%1$s,%2$d" />
</bean>
</property>
</bean>
ここでは、ItemWriterのサンプルのみ示します。
lineAggregatorプロパティに、FormatterLineAggregatorを使用することでprintfと同様のことができます。
しかも、「%要素番号$」で、自由に出力要素を決められます。
これはFormatterというJavaに元々存在する機能ですので、詳しくはjavadocをご確認ください。
要素がDate型の場合、"%1$tY%1$tm%1$td"のように、年、月、日などに分解して出力することもできます。
ItemReaderで読み込んだデータの妥当性チェックをする方法
<!-- 妥当性チェックプロセッサ -->
<bean id="validatingItemProcessor"
class="org.springframework.batch.item.validator.ValidatingItemProcessor">
<property name="validator" ref="validator" />
</bean>
<!-- SpringModules用からSpringBatch用へ変換するためのラッパーValidator。 -->
<bean id="validator" class="org.springframework.batch.item.validator.SpringValidator">
<property name="validator" ref="valangValidator" />
</bean>
<!-- 妥当性チェックするValidator -->
<bean id="valangValidator" class="org.springmodules.validation.valang.ValangValidator">
<property name="valang">
<value>
<![CDATA[
{ id : ? >= 1 AND ? <= 10 : 'IDは1~10です。' : 'errors.range': 'ID',1,10 }
{ name : size(?) <= 10 : '名前は10文字以下です。' : 'errors.maxlength': '名前',10 }
]]>
</value>
</property>
</bean>
妥当性チェックの具体的な方法はこの記事を参考にしてください。
ここでは、SpringコアのValidatorインターフェースを使用する方法をみます。
実は妥当性チェックの方法はSpringのコア機能として用意されていて、SpringBatchに特化したお話ではありません。
しかし、SpringBatchでは少し機能を簡易にするために、使用するインターフェースが別になっていることに注意ください。
具体的には、コアの方ではorg.springframework.validation.Validatorですが、SpringBatchでは、org.springframework.batch.item.validator.Validatorです。
インターフェースは違いますが2つを橋渡しする方法は用意されているので簡単です。
単に、SpringValidatorを使用するだけです。
上記を見ていただければ使い方もわかるかと思います。
その他の補足:
Processorを妥当性チェックに使ってしまうと、他の処理ができないと不安になるかもしれませんが大丈夫です。
ItemProcessorには複数のItemProcessorを実行できるクラスが用意されています。
クラス名は、CompositeItemProcessorになります。このクラスを使用してみてください。
追記: 2014.08.03
上記では、valangValidatorを使用していますが、これはSpringModulesの一部です。
SpringModulesは廃止されたプロジェクトですので使用しない方が良いかと思います。
自作のValidatorを作成するか、Hibernate Validatorを使用するサンプルを書きましたので、そちらを参考にしてみてください。
自作のItemReaderをリスタート可能にする方法
public class RestartableItemReader<T> implements ItemStreamReader<T> {
private int index;
//・・・その他の処理
@Override
public void close() throws ItemStreamException {
}
@Override
public void open(ExecutionContext context) throws ItemStreamException {
this.index = context.getInt(KEY + "index", 0);
//取得したスタート位置まで読み進める(時間が掛からないような工夫をすること)
for(i=0; i<this.index; ++i) read();
}
@Override
public void update(ExecutionContext context) throws ItemStreamException {
context.putInt(KEY + "index", this.index);
}
}
自作した場合、リスタート可能にするには工夫が必要です。
上記のようにItemStreamReaderをimplementsして、stepを開始するイベントと、ItemWriterがコミットするイベントを
受け取れるようにします。
updateメソッドはコミットした後に呼ばれますので、そのたびにStepExecutionContextにコミット数を保存します。
そして、openメソッドはstep開始時に呼ばれますので、StepExecutionContextからコミットした数を取得して
そこから読み込みを開始できるようにします。
注意点としては、openは、初めてstepを開始するときにも、リスタートでstep開始するときにも呼ばれることです。
ですので、リスタート時の処理しか考慮に入れずに実装を記述すると、初めてstep処理をするときに動作がおかしくなるかもしれません。
複数のデータ(もしくは複数の箇所)を読み込む方法
ItemReaderでは1つのitemを読み込み、ItemProcessorやItemWriterに渡します。
このとき、ファイルのデータとDBのデータを同時に読み込んで渡したいような複雑なケース出てきます。
もしくは、DBのデータしか読み込まないのですが、複雑でSQL1つで書き表せないようなケースです。
このような場合は、ItemReaderでキーとなるIDのようなものだけ読み込みます。
これだけであれば、SpringBatchで用意されているクラスだけで可能です。
そして、ItemProcessorを自作して、IDから必要な情報をまとめて取得します。
例えば、複数のSQL文を実行して値を収集してもよいですし、DBから取得してさらにファイルからも取得してもよいです。
取得できましたら、1つのオブジェクトにそれらの値を保存します。Mapや配列に保存しても良いと思います。
それを新しいitemとしてprocess()メソッドから返してあげればよいです。
もしくは、もし、コミットが必要な処理でなければItemProcessorでそのまま処理を実施しても良いと思います。
コミットが必要なものはItemWriterに任せた方が良いので注意が必要です。
なぜなら、リスタート可能にするには、ItemWriterで書き込ませる必要があるからです。
このように対応すれば、ほとんどの処理が可能になると思います。
補足:
SpringBatchでは、ItemProcessorやItemWriterは、複数実行するクラスが用意されています。
CompositeItemProcessorとCompositeItemWriterです。
これらもあわせて使用することでより柔軟な対応ができると思います。
ジョブパラメタやExecutionContextの値をbeanのプロパティで利用する方法(遅延バインディング)
<bean id="flatFileItemReader" scope="step" class="org.springframework.batch.item.file.FlatFileItemReader">
<property name="resource" value="#{jobParameters['input.file.name']}" />
</bean>
上記は、SpringBatch本家のUser Guide5章からの引用です。
SpringBatchでは、上記のようにジョブパラメタをプロパティに使用できます。
形式は、#{種類['キー名']} です。
種類としては、jobParameters、jobExecutionContext、stepExecutionContext、などが使用できます。
注意点としては、必ずscopeを"step"にすることです。
ステップ処理を起動するたびに、jobExecutionContext、stepExecutionContextなどは値が変わる可能性があるからだと思います。
もうひとつ補足しておくと、Springのバージョンによって書き方に差異があるようです。
例えば、Spring2.5ではキー名にシングルクォートをしなくてもエラーにならないようですが、Spring3.0以降ではエラーになるようです。
ItemWriterで「最大オープン・カーソル数を超えました」のようなエラーを解決する方法
この問題を抱えている方はおそらく「ORA-01000」などのOracleのエラーに直面されたのだと思います。
そして、その場合、おそらくですがBatchItemWriterを使用して、1つ前に発行したSQLと違うSQLを発行していませんか?
※この記事は「経験上このように推測される」という内容を書いていますので、その点はご了承ください。
実はいろいろ調べたのですがBatchItemWriterで同様の問題について言及している記事が見つかりませんでした。(2013年現在)
BatchItemWriterで1つ前に発行したのと違うSQLを発行するイメージ例:
String sql = "update A set name=? ";
if(member.id > 100){
sql += ", area=null";
}
sql += " where id=?";
上記のようにmemberオブジェクトの値によってSQLが変わる場合、1つ前に発行したSQLと違うSQLを発行する可能性があります。
例えば上記で、member.idが 100以下、100より大きい、という値を交互に実行した場合、2つのSQLが交互に発行されることになります。
IBatis、MyBatis、Hibernateなどでは、たいていの場合、オブジェクトの値によってSQL文が変わることはよくあると思います。
通常のJdbcの処理は問題ないのですが、Jdbcのバッチ処理(executeBatch)の場合、実行するSQLやオブジェクト(プレースホルダに入れる値)を溜めていき、
最後にまとめて更新処理を実行します。こうすることで処理が早くなります。
基本的には溜めていくオブジェクトは違っても良いですが、実行するSQLは同じであることが求められます。
Oracleの場合は特に、バッチ処理では1つ前のSQL文と変わるたびにカーソルを開くようで、カーソルを開きすぎれば当然、最大オープン数を超えます。
そして、Spring BatchのItemWriterは、Jdbcのバッチ処理を使用しています。
確認方法:
SQL文をログに出力してみてください。
log4jの設定などを変えると出力されます。O/Rマッピングによってやり方が違いますがGoogle検索ですぐ見つかると思います。
このとき、SQL文が変わらない場合、SQL文は1つしか出力されません。しかし、SQL文が変わる場合は変わるたびにSQL文がログに出るようです。
ですので、ログに出力された数を数えると、Oracleに設定されたカーソル最大数で例外が発生しませんか?
(注意点: ログはたいてい、1つのSQL発行でPrepareとExecuteが1セットで出力されます。セット数を数えましょう。間違って2倍の数を数えてしまわないように。)
対策:
対策としては動的に変わらないSQLを使用するようにするのが基本です。
例えば上記であれば、SQL文の中でcaseなどを使って100より大きい場合はnullを、100以下なら同じ値(area=area)を設定するように記述する。
もしくは、member.idが100より大きい場合は、Javaのプログラムの方でareaにnullを設定しておき、SQLは” update A set name=?, area=? where id=?”
というように動的に変わらないようにしておく。などです。
あとはあまりよくないですが、Oracleの場合は設定で最大カーソル数を変更することもできますので、設定値を増やすという手もあります。
しかし、処理数が増えた場合は再度、設定値を増やさなければならず、正しい解決法とは言えないと思います。
タスクレット編
システムコマンドを実行する方法
<job id="jobFile" xmlns="http://www.springframework.org/schema/batch" incrementer="jobParametersIncrementer">
<step id="step1">
<tasklet ref="copyFile" />
</step>
</job>
<bean id="copyFile" class="org.springframework.batch.core.step.tasklet.SystemCommandTasklet">
<property name="command" value="cmd /C copy c:\test.txt c:\test2.txt" />
<property name="timeout" value="30000" />
</bean>
SystemComandTaskletを使用すると、システムコマンドを実行できます。
上記では、Windows上で、ファイルコピーのコマンド実行しています。
この部品は、スレッドを新しく作成して実行し、処理時間を監視します。
そうすることで設定したタイムアウト時間を過ぎたときに、強制的に処理を終了させる処理を実現しています。
ビジネスロジックなどを実行する方法
<job id="jobFile" xmlns="http://www.springframework.org/schema/batch" incrementer="jobParametersIncrementer">
<step id="step1">
<tasklet ref="taskletAdapter" />
</step>
</job>
<bean id="b1" class="com.my.Bussiness1"/>
<bean id="taskletAdapter" class="org.springframework.batch.core.step.tasklet.MethodInvokingTaskletAdapter">
<property name="targetObject" ref="b1" />
<property name="targetMethod" value="execute" />
<property name="arguments" value="10" />
</bean>
ビジネスロジックを実行するのは簡単で、MethodInvokingTaskletAdapterを使用するだけです。
メソッド名と引数を使用して実行できます。
引数プロパティは、上記のサンプルでは1つだけ指定していますが、List型ですのでlistタグを指定して複数指定できます。
また、引数には当然ながら遅延バインディングにより、ジョブパラメタやJobExecutionContextなどの値を指定できます。
【注意点】
このtaskletは、チャンクによるタスクレットと違い、トランザクション管理をしません。
DBを使用しないビジネスロジックであれば問題ありません。
ですがDBを使用する場合、Springトランザクションなどを使用してビジネスロジックに
宣言的トランザクションなどでトランザクションをかけておきましょう。
ジョブ編
JobRepositoryへのジョブの状態の保存時にカラムのサイズを超えてしまうエラーの回避方法
Spring Batchは、テーブルにジョブの状態を保存します。
このとき、Varcharのカラムで、サイズを超えてしまうエラーが発生することがあります。
例えばOracleですと、「ORA-12899」が発生します。
【原因】
SpringBatchでは、サイズを超えないように2500文字を超えると、2500文字に収まるように文字列を切ってくれます。
しかし、全角文字が入っていると、2500バイトに収まらなくなります。
なぜなら、バイトではなくStringの文字数で削除する文字数を決めているからです。
ここでは、このようなエラーが発生したときの回避方法をTipsとして紹介します。
回避方法は主に2つあります。
【回避方法1】
DBのカラムのサイズは、おそらく2500バイトになっているかと思います。
このサイズを3000くらいまで増やせばほぼ大丈夫かと思います。
【回避方法2】
もう一つは、2000文字くらいまで文字列を切って、小さくしてからDBに登録させる方法です。
これも簡単で、JobRepositoryにDIで設定するだけです。
以下のように記述してみてください。
<bean id="jobRepository"
class="org.springframework.batch.core.repository.support.JobRepositoryFactoryBean"
p:dataSource-ref="dataSource" p:transactionManager-ref="transactionManager" p:maxVarCharLength="2000" />
こうすることで、SpringBatchのDAOに渡す前に文字列を小さくしてくれます。
ジョブパラメタ(JobParameters)の妥当性チェックをする方法
public class SampleJobParametersValidator implements JobParametersValidator {
@Override
public void validate(JobParameters params) throws JobParametersInvalidException {
if(params.getLong("no") < 0){
throw new JobParametersInvalidException("noは正の整数です。");
}
}
}
ジョブパラメタの妥当性チェックをするには、上記のようにJobParametersValidator を継承して、Validatorクラスを作ります。
エラーがある場合は、例外を投げるように実装します。
【設定ファイルのサンプル】
<job id="job" xmlns="http://www.springframework.org/schema/batch" incrementer="jobParametersIncrementer" >
<validator ref="sampleJobParametersValidator" />
<step id="step1" parent="simpleStep" >
・・・
</step>
</job>
<!-- beanは、validatorタグの中に記述することもできます -->
<bean id="sampleJobParametersValidator" class="sample.SampleJobParametersValidator" />
設定も簡単で、上記のようにvalidatorタグを記述するだけです。
妥当性チェックでエラーが発生すると、JobInstanceやJobExecutionなどのオブジェクトが生成されません。
当然、DBのバッチ用の管理テーブルにも何も保存されません。
ちなみに、ValangやCommonsValidatorを使用できると楽なのですが、SpringBatchはそのような機能を持っていません。
しかし、soracaneでは用意していますので、一度ご確認いただければと思います。
条件分岐する方法
条件分岐を記述する方法はいくつかあります。
以下のサンプルはSpringBatch本家のページのUser Guideの5章を引用して記述しています。
【SpringBatchでデフォルトで用意している簡易な方法】
内容については、こちらを参照ください。他の記事で記述しています。
【stepリスナーを利用する方法】
public class ChangeStatusListener implements StepExecutionListener {
@Override
public ExitStatus afterStep(StepExecution se) {
//seの値などによってreturn値を変更する(以下はItemReaderなどでスキップした数で判断)
if(se.getSkipCount() > 0){
return new ExitStatus("SKIP");
}
return null;
}
@Override
public void beforeStep(StepExecution se) {
}
}
afterStepの返り値を変更することでExitStatusをコントロールできます。
この後、ステップの設定で、以下のようにします。いくつかbeanの設定などは省略しています。
<step id="test" parent="simpleStep">
<tasklet>
<listeners>
<listener ref="changeStatusListener" />
</listeners>
</tasklet>
<next on="SKIP" to="step2"/>
<next on="*" to="step3"/>
</step>
【deciderを利用する方法】
public class MyDecider implements JobExecutionDecider {
public FlowExecutionStatus decide(JobExecution jobExecution, StepExecution stepExecution) {
if (someCondition) {
return new FlowExecutionStatus("SKIP NEXT");
}
else {
return FlowExecutionStatus.COMPLETED;
}
}
}
リスナーのときのように、インターフェースをimplementsして返り値を変更します。
引数のstepExecutionは、1つ前のstepの実行結果が入っています。
リスナーを作成しましたら、以下のようにstepとstepの間に入れて、条件分岐に使用します。
<job id="job" xmlns="http://www.springframework.org/schema/batch">
<step id="step1" parent="s1" next="decision" />
<decision id="decision" decider="myDecider">
<next on="SKIP NEXT" to="step2" />
<next on="COMPLETED" to="step3" />
</decision>
<step id="step2" parent="s2" next="step3"/>
<step id="step3" parent="s3" />
</job>
並行処理をする方法
並行処理は、jobタグに記述すだけで可能です。
簡単ですので記述サンプルのみ示します。
<split id="split1" next="step4">
<flow>
<step id="step1" parent="sp1" next="step2"/>
<step id="step2" parent="sp2"/>
</flow>
<flow>
<step id="step3" parent="sp3"/>
</flow>
</split>
<step id="step4" parent="sp4"/>
上記のようにsplitタグを使用することで、スレッドを複数作成して並行処理をしてくれます。
ちなみにflowタグは、splitタグ内に記述するだけでなく、jobの外で定義することもできます。
また、jobの内部でその定義を参照することができるため、使いまわしにも使用できます。
そのTipsは以下で記述していますので参照してみてください。
ジョブを細分化して、再利用する方法
SpringBatchでは、複数のstepをひとかたまりにして、jobの中で参照することができます。
本家のページのUser Guideで紹介されているのは以下の3つです。
(記述は引用をしていますが、2番目の方法は本家が間違っていたので正しく直しました。)
3つともバッチで処理される内容は同じです。
違いは、SpringBatchの管理テーブルへのジョブの実行結果の登録の仕方です。
【①jobタグ内で直接flowタグを使用する方法】
<job id="job">
<flow id="job1.flow1" parent="flow1" next="step3"/>
<step id="step3" parent="s3"/>
</job>
<flow id="flow1">
<step id="step1" parent="s1" next="step2"/>
<step id="step2" parent="s2"/>
</flow>
この方法ですと、job内のflowタグが、丁度下のflowタグで置き換わる感じになります。
ですので、StepExecutionテーブルにはstep1、step2のレコードが作製されます。
【②stepタグ内でflowタグを使用する方法】
<job id="job">
<step id="job1.flow1" next="step3">
<flow id="flow1" />
</step>
<step id="step3" parent="s3"/>
</job>
この方法ですと、StepExecutionテーブルには、job1.flow1、step1、step2のレコードが作製されます。
【③jobタグ内でjobタグを使用する方法】
<job id="jobStepJob" restartable="true">
<step id="jobStepJob.step1">
<job ref="job1" job-launcher="jobLauncher"
job-parameters-extractor="jobParametersExtractor"/>
</step>
</job>
<job id="job1" restartable="true">...</job>
<bean id="jobParametersExtractor" class="org.spr...DefaultJobParametersExtractor">
<property name="keys" value="input.file"/>
</bean>
この方法ですと、JobInstance自体が2つ作成されます。(2つのジョブを実行したようにレコードが作成されます。)
ですので、例えばジョブ"jobStepJob"を実行した後に、同じパラメタで細分化したジョブ"job1"を実行すると、既に実行済みといった例外が発生します。
また、ジョブ"jobStepJob"を実行したとき、StepExecutionについても、2つのジョブを実行した時と同様の作成のされ方がされます。
job-parameters-extractorは、親のjobが受け取ったジョブパラメタのうち一部のパラメタのみ受け取りたい時に使用するようです。
この属性を記述しなければ、親のjobと同じジョブパラメタで起動します。
プログラム上からジョブを実行する方法
他の記事でコマンドラインからSpring Batchを実行する方法を紹介しました。
ここでは、Javaのプログラム上からジョブを実行する方法を見ていきます。
主な方法を以下に記述します。(準備は「05.使用するための準備」を参照)
【①JobLauncherを利用する方法】
Job job = (Job)applicationContext.getBean("job1")
JobLauncher jobLauncher = (JobLauncher)applicationContext.getBean("jobLauncher");
//ジョブパラメタの作成
Map<String, JobParameter> param = new HashMap<String, JobParameter>();
param.put("name", new JobParameter("taro"));
param.put("date", new JobParameter("2010/01/27"));
JobParameters jp = new JobParameters(param);
//実行
jobLauncher.run(job, jp);
jobLauncherを利用します。
もちろんSpringの設定ファイルに設定しておく必要があります。
この方法ですと、コマンドラインの起動方法でいうオプションの機能は使用できません。
しかし、もっともシンプルな方法です。
【②JobOperatorを利用する方法】
JobOperator jobOperator = (JobOperator)applicationContext.getBean("jobOperator");
jobOperator.start("job1", "name=taro date=2010/01/27");
jobOperator は、コマンドラインの方法に近いです。
ジョブ名とパラメタを指定して実行します。
startメソッドの他にrestart、stop、startNextInstanceなどもできます。
start()の返り値はジョブ実行IDになりますので、その値を受けてrestartできます。
restartの引数はジョブ実行IDです。
JUnitでリスタートのテストをするときにも便利です。
(参考:03.Spring Batchの基本概念(起動と起動オプション))
ジョブを非同期で実行する方法
<bean id="jobLauncher" class="org.springframework.batch.core.launch.support.SimpleJobLauncher">
<property name="jobRepository" ref="jobRepository" />
<property name="taskExecutor">
<bean class="org.springframework.core.task.SimpleAsyncTaskExecutor" />
</property>
</bean>
ジョブを非同期で実行するのは簡単です。
上記のように、jobLauncherを書き換えて、SimpleAsyncTaskExecutorを使用するだけです。
コマンドラインから実行するときは非同期にすることはありませんが、WEBなどから実行する場合には便利です。
WEBから実行する方法は、上記Tips「プログラム上からジョブを実行する方法」もあわせてご覧ください。
その他
ログ出力に"Executing step:..."などを出力しない方法
SpringBatchのログはINFOレベルでもかなり色々と出力されます。
デバッグ時は助かるのですが、運用してみると少し邪魔になることもあります。
そこで、"Executing step:..."などのINFOレベルのログを別ファイルに出力する方法をここで見てみましょう。
この方法は、Log4jの機能をそのまま使用しますが、xmlで記述しなければできないことに注意してください。
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">
<appender class="org.apache.log4j.RollingFileAppender" name="batchDebug">
<param value="C:/batch-debug.log" name="File"/>
<param value="true" name="Append"/>
<param value="UTF-8" name="Encoding"/>
<param value="3" name="MaxBackupIndex"/>
<param value="3MB" name="MaxFileSize"/>
<layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern" value="%d{yyyy/MM/dd HH:mm:ss.SSS} %p %m%n"/>
</layout>
</appender>
<appender class="org.apache.log4j.RollingFileAppender" name="app">
<param value="C:/app.log" name="File"/>
<param value="UTF-8" name="Encoding"/>
<param value="true" name="Append"/>
<param value="3" name="MaxBackupIndex"/>
<param value="1MB" name="MaxFileSize"/>
<layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern" value="%d{yyyy/MM/dd HH:mm:ss.SSS} %p %m%n"/>
</layout>
<!--
フィルタをかける。ログレベルと、出力メッセージに含まれる文字列でフィルタする。
-->
<filter class="org.apache.log4j.varia.LevelMatchFilter">
<param name="LevelToMatch" value="FATAL" />
<param name="AcceptOnMatch" value="true" />
</filter>
<filter class="org.apache.log4j.varia.LevelMatchFilter">
<param name="LevelToMatch" value="ERROR" />
<param name="AcceptOnMatch" value="true" />
</filter>
<filter class="org.apache.log4j.varia.StringMatchFilter" >
<param name="StringToMatch" value="Executing step:" />
<param name="AcceptOnMatch" value="false" />
</filter>
<!-- バッチの開始・終了ログも出したくない場合は以下のコメントをはずす -->
<!-- filter class="org.apache.log4j.varia.StringMatchFilter">
<param name="StringToMatch" value="Job: [FlowJob: [name=" />
<param name="AcceptOnMatch" value="false" />
</filter -->
</appender>
<logger name="org.springframework.batch" additivity="false">
<level value="INFO"/>
<appender-ref ref="app"/>
<appender-ref ref="batchDebug"/>
</logger>
<root>
<level value="ERROR"/>
<appender-ref ref="app"/>
</root>
</log4j:configuration>
上記のようにすることで、app.logファイルには、"Executing step:..."というログのみが出力されなくなります。
また、batch-debug.logファイルには、SpringBatchのすべてのログが出力されます。
2つあわせれば故障時の解析もできます。
ログに"No database type set, ..."が出力されないようにする方法
ログに"No database type set, ..."というINFOレベルのメッセージが出力される方がいるかもしれません。
これは、SpringBatchがLOBなどの処理のためDBのタイプ(ORACLE、MYSQLなど)を知りたいために出力されます。
以下のように明示的にDBタイプを指定すれば出なくなります。
<bean id="jobRepository" p:databaseType="POSTGRES"
class="org.springframework.batch.core.repository.support.JobRepositoryFactoryBean"
p:dataSource-ref="dataSource" p:transactionManager-ref="transactionManager" />
赤字の部分が指定されない場合、SpringBatchはDataSourceの情報から何のDBなのかを推測します。
このときに推測したDBタイプを出力したものが表題のログになります。
ちなみに、databaseTypeに記述できる文字列は、DatabaseTypeクラスのJavadocを参照すれば分かります。
(HSQL, SQLSERVER, MYSQL, ORACLE, POSTGRES、など)
JobRepositoryについて記述した以下の記事も参照ください。
Created Date: 2010/12/12