我们使用Spring Batch从CSV文件中读取记录并插入到数据库表中 .
Datasource and transaction manager
<!-- connect to database -->
<bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="oracle.jdbc.OracleDriver" />
<property name="url" value="**********" />
<property name="username" value="**********" />
<property name="password" value="**********" />
</bean>
<bean id="transactionManagerTest"
class="org.springframework.batch.support.transaction.ResourcelessTransactionManager" />
JOB Configuration
<!-- 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="transactionManagerTest" />
<property name="databaseType" value="Oracle" />
</bean>
<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>
Below is spring batch job configuration
<batch:job id="reportJob">
<batch:step id="step1" >
<batch:tasklet transaction-manager="transactionManagerTest" >
<batch:chunk reader="cvsFileItemReader" writer="mysqlItemWriter" commit-interval="5" skip-limit="1000" processor-transactional="true">
<!--
<batch:skip-policy>
<bean class="org.springframework.batch.core.step.skip.AlwaysSkipItemSkipPolicy" scope="step"/>
</batch:skip-policy> -->
<batch:skippable-exception-classes>
<batch:include class="java.lang.Exception" />
</batch:skippable-exception-classes>
<!-- <batch:retry-policy>
<bean class="org.springframework.retry.policy.NeverRetryPolicy" scope="step"/>
</batch:retry-policy> -->
<batch:listeners>
<batch:listener ref="itemWriterListner"/>
</batch:listeners>
</batch:chunk>
</batch:tasklet>
</batch:step>
</batch:job>
这里我们定义了 batch:skippable-exception-classes ,如果任何记录插入语句失败,它应该用于处理 .
举一个例子,我们在csv文件中有10条记录,我们一个接一个地读取并插入数据库中的数据库中,但是在第四条记录插入失败之前,它应该继续第5条记录以及应该只跳过第4条记录 .
但是对于 batch:skippable-exception-classes ,如果第4条记录失败,它将再次从第1条记录继续 . 所以在数据库表中我们有1-3次记录2次(重复记录)
请提示,如果我遗漏了 spring 批的任何配置属性 .
4 回答
这是在写入阶段发生异常时的标准行为 .
项目(从1到5)是逐个写入的,但是作为单个块提交,如果发生错误,SB无法检测应该跳过哪个项目,SB如何决定哪个项目应该是跳过?
SB再次开始写入阶段,但逐项写入项目(如设置
commit-interval="1"
)以检测坏项并将其发送到SkipListener.skipInWrite(item,exception)
.关于项目重复使用SELECT / UPDATE策略而不是简单的INSERT写入 .
定义事务管理器如下
这应该可以解决问题 .
配置事务管理器的方式有问题(上面的配置中没有包含) . 虽然bellabax是正确的,因为当写入的项目抛出异常时,整个块被回滚并且每个项目被单独处理/写入以确定块中的哪个项目导致错误,关键点似乎不是为你工作的是实际的回滚 .
UPDATE
ResourcelessTransactionManager
isn 't a real transaction manager and is not intended for use with transactional resources (like databases). Configure your job with a real transaction manager and you'没事 .我相信这仍然是一项正在进行中的工作 . 见JIRA issue和this one . 它已经讨论了很长一段时间了:Spring论坛post 1和post 2 . 也许对两个JIRA问题进行一些额外投票会使它们变得更加重要并且更有可能被添加 .