Spring Batch后续步骤如何读取前置步骤更新的表数据?
Spring Batch多Step数据更新异常排查与解决
问题场景
创建包含两个Step的Spring Batch Job:
- Step1:读取Oracle表中含特定字符的条目,更新移除该字符
- Step2:读取上述Oracle表的更新后数据,迁移至Sybase数据库
测试发现Step2始终读取Step1更新前的数据,排查后发现两个核心问题:事务管理器配置不匹配、更新SQL语句错误。
初始Job配置
<job id="example-job" job-repository="jobRepository" xmlns="http://www.springframework.org/schema/batch"> <step id="update_table" parent="simpleStep" next="use_updated_data"> <!-- step 1 --> <tasklet> <chunk writer="updateTableItemWriter" reader="updateTableItemReader" commit-interval="100"/> </tasklet> </step> <step id="use_updated_data" parent="simpleStep"> <!-- step 2 --> <tasklet> <chunk writer="useUpdatedTableItemWriter" reader="useUpdatedTableItemReader" commit-interval="100"/> </tasklet> </step> </job>
读写组件与Step父类配置
<beans:bean name="updateTableItemReader" scope="step" class="org.springframework.batch.item.database.JdbcCursorItemReader"> <beans:property name="dataSource" ref="oracleDS" /> <beans:property name="sql" value="${read.findEntriesWithChar}"> </beans:property> <beans:property name="rowMapper"> <beans:bean name="mapper" class="com.myProj.batch.tableRowMapper" /> </beans:property> </beans:bean> <beans:bean id="updateTableItemWriter" class="org.springframework.batch.item.database.JdbcBatchItemWriter"> <beans:property name="assertUpdates" value="false" /> <beans:property name="itemSqlParameterSourceProvider"> <beans:bean name="sqlParameterSourceProvider" class="org.springframework.batch.item.database.BeanPropertyItemSqlParameterSourceProvider" /> </beans:property> <beans:property name="sql" value="${write.updateEntriesReplaceChar}"/> <beans:property name="dataSource" ref="oracleDS" /> </beans:bean> <beans:bean name="useUpdatedTableItemReader" scope="step" class="org.springframework.batch.item.database.JdbcCursorItemReader"> <beans:property name="dataSource" ref="oracleDS" /> <beans:property name="sql" value="${read.useUpdatedTableNoChar}"> </beans:property> <beans:property name="rowMapper"> <beans:bean name="mapper" class="com.myProj.batch.tableRowMapper" /> </beans:property> </beans:bean> <beans:bean id="useUpdatedTableItemWriter" class="org.springframework.batch.item.database.JdbcBatchItemWriter"> <beans:property name="assertUpdates" value="false" /> <beans:property name="itemSqlParameterSourceProvider"> <beans:bean name="sqlParameterSourceProvider" class="org.springframework.batch.item.database.BeanPropertyItemSqlParameterSourceProvider" /> </beans:property> <beans:property name="sql" value="${write.useUpdatedTableNoCharTransfer}"/> <beans:property name="dataSource" ref="sybaseDS" /> </beans:bean> <beans:bean id="simpleStep" class="org.springframework.batch.core.step.item.SimpleStepFactoryBean" abstract="true"> <beans:property name="transactionManager" ref="transMan_sybase" /> <beans:property name="jobRepository" ref="jobRepository" /> <beans:property name="startLimit" value="100" /> <beans:property name="commitInterval" value="1" /> </beans:bean>
核心问题与解决方案
1. 事务管理器与数据源不匹配
Step1操作Oracle数据库,但继承的simpleStep使用了Sybase的事务管理器transMan_sybase,导致Step1的事务无法正确提交至Oracle,数据更新未持久化。
修正方案:
- 为Oracle单独配置事务管理器:
<beans:bean id="transMan_oracle" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <beans:property name="dataSource" ref="oracleDS" /> </beans:bean>
- 拆分抽象Step,分别对应Oracle和Sybase:
<!-- Oracle操作的抽象Step --> <beans:bean id="oracleSimpleStep" class="org.springframework.batch.core.step.item.SimpleStepFactoryBean" abstract="true"> <beans:property name="transactionManager" ref="transMan_oracle" /> <beans:property name="jobRepository" ref="jobRepository" /> <beans:property name="startLimit" value="100" /> <beans:property name="commitInterval" value="1" /> </beans:bean> <!-- Sybase操作的抽象Step --> <beans:bean id="sybaseSimpleStep" class="org.springframework.batch.core.step.item.SimpleStepFactoryBean" abstract="true"> <beans:property name="transactionManager" ref="transMan_sybase" /> <beans:property name="jobRepository" ref="jobRepository" /> <beans:property name="startLimit" value="100" /> <beans:property name="commitInterval" value="1" /> </beans:bean>
- 修改Job中Step的父类:
<step id="update_table" parent="oracleSimpleStep" next="use_updated_data"> <!-- 使用Oracle事务管理器 --> <step id="use_updated_data" parent="sybaseSimpleStep"> <!-- 使用Sybase事务管理器 -->
2. 更新SQL语句错误
原.properties中的更新SQL因关键字未转义导致执行失败:
-- 原错误SQL SET desc = replace(desc, UNISTR('\2013'), '-') WHERE desc like '%' || UNISTR('\2013') || '%'
修正方案:
Oracle中desc是排序关键字,作为列名必须用英文双引号包裹;UNISTR的\2013写法符合U+2013字符的编码规则,修正后的SQL:
SET "desc" = replace("desc", UNISTR('\2013'), '-') WHERE "desc" like '%' || UNISTR('\2013') || '%'
若在.properties文件中配置,需注意双引号的转义规则,可直接使用"desc"或转义为\"desc\"。
内容的提问来源于stack exchange,提问作者Vincere
相关产品推荐
相关产品推荐

