2

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>
Emeres
  • 33
  • 1
  • 5
  • Did you check if you turned OFF autocommit on your datasource? What you observe is exactly what happens if autocommit is set to true. – Hansjoerg Wingeier May 27 '16 at 20:17
  • In datasource I changed class for `class="org.apache.commons.dbcp.BasicDataSource"` because `org.springframework.jdbc.datasource.DriverManagerDataSource` not has option to setting autocommit. And now when I set autoCommit=false, in my database any data are not saved. But when I set autoCommit=true i have the same situation which I described above (duplicated data) – Emeres May 27 '16 at 22:50
  • And summary for step execution look: `StepExecution: id=1, version=4, name=step1, status=COMPLETED, exitStatus=COMPLETED, readCount=3, filterCount=0, writeCount=2 readSkipCount=0, writeSkipCount=1, processSkipCount=0, commitCount=3, rollbackCount=2`. readCount and writeCount i think it is ok but commitCount=3 – Emeres May 27 '16 at 23:06
  • You have to set autocommit to false. Otherwise, spring-batch cannot manage your transactions. – Hansjoerg Wingeier May 28 '16 at 04:44
  • There could be a problem with your transaction manager definition. Moreover, you are using a Map-based job repository. This is ok to do a little testing. But I don't know how it behaves concerning transactions. – Hansjoerg Wingeier May 28 '16 at 04:48
  • Its looks like the problem (as you said) was in transactionManager. I used transactionManager from `org.springframework.batch.support.transaction.ResourcelessTransactionManager` in both cases: in JobRepository and in job's tasklet declaration. After changing transaction manager in job's tasklet declaration for `org.springframework.jdbc.datasource.DataSourceTransactionManager` - job works as I expected. – Emeres May 28 '16 at 13:38
  • I need read more documentation about ResourcelessTransactionManager but Is it possible that this transaction manager no manage transaction in batch job and only it works in meta-data job repository? In some examples I saw that only ResourcelessTransactionManager was used. @HansjoergWingeier thank you for your help. – Emeres May 28 '16 at 13:38

0 Answers0