Spring批处理回滚所有块&;一次写一个文件
我是春季的新手,我有几个问题 问题1:我使用MultiResourceItemReader读取一堆CSV文件,使用JDBC项目编写器批量更新数据库。提交间隔设置为1000。如果有一个文件包含10k记录,并且我在第7批中遇到了DB错误,有没有办法回滚以前提交的所有数据块Spring批处理回滚所有块&;一次写一个文件,spring,spring-batch,Spring,Spring Batch,我是春季的新手,我有几个问题 问题1:我使用MultiResourceItemReader读取一堆CSV文件,使用JDBC项目编写器批量更新数据库。提交间隔设置为1000。如果有一个文件包含10k记录,并且我在第7批中遇到了DB错误,有没有办法回滚以前提交的所有数据块 问题2:如果有两个文件各有100条记录,且提交间隔设置为1000,则MultiResourceItemReader将读取这两个文件并将其发送给编写器。有没有办法一次只写一个文件而忽略提交间隔?在这种情况下,实际上是在writer中
问题2:如果有两个文件各有100条记录,且提交间隔设置为1000,则MultiResourceItemReader将读取这两个文件并将其发送给编写器。有没有办法一次只写一个文件而忽略提交间隔?在这种情况下,实际上是在writer中单独创建一个循环?问题1:实现这一点的唯一方法是通过某种形式的补偿逻辑。您可以通过监听器(例如,
ChunkListener#afterChunkError
)实现这一点,但具体实现取决于您。Spring批处理中没有任何东西知道输出的总体状态是什么,以及如何将其回滚到当前事务之外
问题2:假设您要为每个输入文件寻找一个输出文件,由于大多数
资源
实现都是非事务性的,与它们相关联的编写器会进行特殊工作,以缓冲到提交点,然后刷新。这里的问题是,正因为如此,没有真正的机会将缓冲区划分为多个资源。明确地说,这是可以做到的,你只需要一个定制的ItemWriter
就可以做到。发布对我有用的解决方案,以防有人需要它作为参考
对于问题1,我可以使用编写器中的StepListenerSupport
实现它,并覆盖BeforeStep
和AfterStep
。示例代码段如下所示
public class JDBCWriter extends StepListenerSupport implements ItemWriter<MyDomain>{
private boolean errorFlag;
private String sql = "{ CALL STORED_PROC(?, ?, ?, ?, ?) }";
@Autowired
private JdbcTemplate jdbcTemplate;
@Override
public void beforeStep(StepExecution stepExecution){
try{
Connection connection = jdbcTemplate.getDataSource().getConnection();
connection.setAutoCommit(false);
}
catch(SQLException ex){
setErrorFlag(Boolean.TRUE);
}
}
@Override
public void write(List<? extends MyDomain> items) throws Exception{
if(!items.isEmpty()){
CallableStatement callableStatement = connection.prepareCall(sql);
callableStatement.setString("1", "FirstName");
callableStatement.setString("2", "LastName");
callableStatement.setString("3", "Date of Birth");
callableStatement.setInt("4", "Year");
callableStatement.registerOutParameter("errors", Types.INTEGER, "");
callableStatement.execute();
if(errors != 0){
this.setErrorFlag(Boolean.TRUE);
}
}
else{
this.setErrorFlag(Boolean.TRUE);
}
}
@Override
public void afterChunk(ChunkContext context){
if(errorFlag){
context.getStepContext().getStepExecution().setExitStatus(ExitStatus.FAILED); //Fail the Step
context.getStepContext().getStepExecution().setStatus(BatchStatus.FAILED); //Fail the batch
}
}
@Override
public ExitStatus afterStep(StepExecution stepExecution){
try{
if(!errorFlag){
connection.commit();
}
else{
connection.rollback();
stepExecution.setExitStatus(ExitStatus.FAILED);
}
}
catch(SQLException ex){
LOG.error("Commit Failed!" + ex);
}
return stepExecution.getExitStatus();
}
public void setErrorFlag(boolean errorFlag){
this.errorFlag = errorFlag;
}
}
公共类JDBCWriter扩展StepListenerSupport实现ItemWriter{
私有布尔错误标志;
私有字符串sql=“{CALL STORED_PROC(?,,,,?,?)}”;
@自动连线
私有JdbcTemplate JdbcTemplate;
@凌驾
预处理前的公共无效(步骤执行步骤执行){
试一试{
连接连接=jdbcTemplate.getDataSource().getConnection();
connection.setAutoCommit(false);
}
catch(SQLException-ex){
setErrorFlag(Boolean.TRUE);
}
}
@凌驾
公开无效写入(ListThank!关于问题2,我正在考虑使用某种类型的PeakableItemReader
实现自定义的CompletionPolicy
,但它运行在一个无限循环中。是否有关于如何将MultiResourceItemReader
与PeakableItemReader
连接起来的工作示例?对于问题2,您不需要要修复读卡器中的内容,您需要修复编写器中的内容。您将已经知道资源已更改(假设您正在对项目使用MultiResourceItemReader
和ResourceAware
)。您只需要在写入时为每个资源创建一个新的缓冲区,并在提交点将其刷新到相应的资源。正如您所建议的,我正在对该项使用MultiResourceItemReader
和ResourceAware
,关于每个资源的缓冲区,您能否详细说明,并在可能的情况下为我指出任何示例?谢谢!我愿意没有示例。但是我可以想象一个映射,在该映射中,您根据通过的资源写入相应的StringBuilder
。然后,当提交发生时,将每个StringBuilder
刷新到正确的资源。通过查看FlatFileItemWr,您可以看到缓冲区处理和刷新是如何工作的国际热核实验堆
。
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
....
http://www.springframework.org/schema/batch/spring-batch-3.0.xsd">
<job id="fileLoadJob" xmlns="http://www.springframework.org/schema/batch">
<step id="batchFileUpload" >
<tasklet>
<chunk reader="fileReader"
commit-interval="1000"
writer="JDBCWriter"
/>
</tasklet>
</step>
</job>
<bean id="fileReader" class="...com.FileReader" />
<bean id="JDBCWriter" class="...com.JDBCWriter" />
</beans>