I have Spring batch job with chunk and setting commit-interval="3" and declared skipable exceptions. I want to save 3 item in DB: item_1 item_2 item_3
Say, I want to save this items in database but second item is invalid and an exception is occured. In this situation should couse rollback and Spring Batch should rerun each item of the problematic chunk individually with one commit/transaction for each item. So in database should be saved item_1 and item_3.
But in my case in database is saved: item_1 item_1 item_3 So item_1 is duplicated. It's look like that item_1 is committed before occuring exception or there is no rollback after occuring exception.
I spent all day on this case and still don't know what is wrong.
Below, Spring batch job configuration. Do you have any idea what is wrong?
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:batch="http://www.springframework.org/schema/batch" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/batch
http://www.springframework.org/schema/batch/spring-batch.xsd
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="marketData" class="net.skwaro.iftpp.model.MarketData" scope="prototype" />
<bean id="itemProcessor" class="net.skwaro.iftpp.job.custom.CustomItemProcessor" scope="prototype" />
<bean id="customStepListener" class="net.skwaro.iftpp.job.listeners.CustomStepListener" scope="prototype" />
<bean id="customProcessListener" class="net.skwaro.iftpp.job.listeners.CustomProcessListener" scope="prototype" />
<bean id="customWriterListener" class="net.skwaro.iftpp.job.listeners.CustomWriterListener" scope="prototype" />
<batch:job id="fetchingMarketDataJob" >
<batch:step id="step1" >
<batch:tasklet transaction-manager="transactionManager">
<batch:chunk reader="outputFileItemReader" writer="mysqlItemWriter" processor="itemProcessor"
commit-interval="3" skip-limit="3" >
<batch:listeners>
<batch:listener ref="customStepListener" />
<batch:listener ref="customProcessListener" />
<batch:listener ref="customWriterListener" />
</batch:listeners>
<batch:skippable-exception-classes>
<batch:include class="java.lang.Exception" />
<batch:include class="java.sql.SQLException" />
<batch:include class="org.springframework.jdbc.UncategorizedSQLException" />
</batch:skippable-exception-classes>
</batch:chunk>
</batch:tasklet>
</batch:step>
</batch:job>
<bean id="outputFileItemReader" class="org.springframework.batch.item.file.FlatFileItemReader">
<property name="resource" value="file:D:\WLS12c\output.txt" />
<property name="lineMapper">
<bean class="net.skwaro.iftpp.job.custom.CustomLineMapper">
<property name="lineTokenizer">
<bean
class="org.springframework.batch.item.file.transform.DelimitedLineTokenizer">
<property name="delimiter" value="|"/>
</bean>
</property>
<property name="fieldSetMapper">
<bean class="net.skwaro.iftpp.job.mappers.MarketDataFieldSetMapper" />
</property>
</bean>
</property>
</bean>
<bean id="mysqlItemWriter"
class="org.springframework.batch.item.database.JdbcBatchItemWriter">
<property name="dataSource" ref="dataSource" />
<property name="sql">
<value>
<![CDATA[
insert into TEST_TABLE(NAME,SOURCE,MONEY_VALUE)
values (:name, :source, :moneyValue)
]]>
</value>
</property>
<property name="itemSqlParameterSourceProvider">
<bean
class="org.springframework.batch.item.database.BeanPropertyItemSqlParameterSourceProvider" />
</property>
</bean>
</beans>
applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:task="http://www.springframework.org/schema/task"
xmlns:util="http://www.springframework.org/schema/util" xmlns:context="http://www.springframework.org/schema/context"
xmlns:batch="http://www.springframework.org/schema/batch"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd
http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task.xsd
http://www.springframework.org/schema/batch
http://www.springframework.org/schema/batch/spring-batch.xsd">
<task:annotation-driven />
<context:annotation-config></context:annotation-config>
<context:component-scan base-package="net.skwaro.iftpp"></context:component-scan>
<import resource="../WEB-INF/fetch-job.xml" />
<context:property-placeholder location="classpath:configuration.properties"
ignore-unresolvable="true" />
<util:properties id="database" location="classpath:database.properties"/>
<bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="url" value="#{database['jdbc.url']}" />
<property name="username" value="#{database['jdbc.username']}" />
<property name="password" value="#{database['jdbc.password']}" />
</bean>
<bean id="jobRepository"
class="org.springframework.batch.core.repository.support.MapJobRepositoryFactoryBean">
<property name="transactionManager" ref="transactionManager" />
</bean>
<!-- stored job-meta in database -->
<!-- <bean id="jobRepository" class="org.springframework.batch.core.repository.support.JobRepositoryFactoryBean">
<property name="dataSource" ref="dataSource" /> <property name="transactionManager"
ref="transactionManager" /> <property name="databaseType" value="mysql" />
</bean> -->
<bean id="transactionManager"
class="org.springframework.batch.support.transaction.ResourcelessTransactionManager" />
<bean id="jobLauncher"
class="org.springframework.batch.core.launch.support.SimpleJobLauncher">
<property name="jobRepository" ref="jobRepository" />
</bean>
</beans>