Spring 批处理步骤未立即提交事务
Spring Batch step not committing transaction immediately
我配置了读取和验证数据的步骤。如果任何验证失败,我将错误 [=18=](创建以跟踪文件详细信息)状态更新为失败,并将原因更新为验证消息(BatchFileDetail 在下面的代码中为错误 table)。
一旦将其保存在数据库中,我立即根据错误 table 状态
抛出异常
下面是我的代码
@Bean
public Job fileParserJob() {
return jobBuilderFactory.get("fileParserJob")
.incrementer(new RunIdIncrementer())
.start(validateFileStep())
.build();
}
public Step validateFileStep() {
return stepBuilderFactory.get("validateFileStep")
.tasklet(fileTasklet)
.build();
}
@Override
@Transactional(dontRollbackOn=BatchServiceException.class)
public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws
Exception {
Resource resource = new FileSystemResource(filePath);
BatchFileDetail batchFileDetail = new BatchFileDetail();
batchFileDetail.setFileId(String.valueOf(System.currentTimeMillis()));
batchFileDetail.setFileName(resource.getFilename());
batchFileDetail.setStatus("STARTED");
batchFileDetail.setProcessedOn(new Date());
CommonUtillity.validateBatchResource(resource, StringConstants.FILE_NAME, batchFileDetail);
validateBatchFileDetail(resource.getFile(), batchFileDetail);
batchFileDetailRepository.saveAndFlush(batchFileDetail);
if(CBOSConstants.FAILED.equals(batchFileDetail.getStatus())) {
throw new BatchServiceException(batchFileDetail.getReason());
}
return RepeatStatus.FINISHED;
}
}
但是我在错误 table 中保存的数据正在回滚。处理异常会导致继续执行另一个步骤,但我想终止当前作业并输入错误 table。
任何帮助表示赞赏。
您正在使用 @Transactional(dontRollbackOn=BatchServiceException.class)
注释您的 tasklet。这不是告诉 Spring Batch 不回滚给定异常类型的事务的方法。
您的 tasklet 将在由 Spring 批处理控制的事务范围内执行,您可以通过事务属性自定义批处理,请参阅 AbstractTaskletStepBuilder#transactionAttribute。
所以在你的情况下,你应该能够通过删除 tasklet 上的 @Transactional
来实现你的要求,并用类似的东西定义你的步骤:
@Bean
public Step validateFileStep() {
TransactionAttribute transactionAttributes = new DefaultTransactionAttribute() {
@Override
public boolean rollbackOn(Throwable exception) {
return !(exception instanceof BatchServiceException);
}
};
return stepBuilderFactory.get("validateFileStep")
.tasklet(fileTasklet)
.transactionAttribute(transactionAttributes)
.build();
}
这是一个简单的 tasklet。对于面向块的 tasklet,可以使用 FaultTolerantStepBuilder#noRollback(Class).
我找到的解决方案可能不是最好的,但根据目前的情况,我会继续进行以下操作。
@Bean
public Job fileParserJob() {
return jobBuilderFactory.get("fileParserJob")
.incrementer(new RunIdIncrementer())
.start(validateFileStep())
.next(validateFileStatusStep())
.build();
}
public Step validateFileStep() {
return stepBuilderFactory.get("validateFileStep")
.tasklet(fileTasklet)
.build();
}
public Step validateFileStatusStep() {
return stepBuilderFactory.get("validateFileStatusStep")
.tasklet(validateBatchFileDetailTasklet)
.build();
}
FileTasklet.java
-----------------
@Override
@Transactional(dontRollbackOn=BatchServiceException.class)
public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws Exception {
Resource resource = new FileSystemResource(filePath);
BatchFileDetail batchFileDetail = new BatchFileDetail();
batchFileDetail.setFileId(String.valueOf(System.currentTimeMillis()));
batchFileDetail.setFileName(resource.getFilename());
batchFileDetail.setStatus("STARTED");
batchFileDetail.setProcessedOn(new Date());
CommonUtillity.validateBatchResource(resource, StringConstants.FILE_NAME, batchFileDetail);
validateBatchFileDetail(resource.getFile(), batchFileDetail);
batchFileDetailRepository.saveAndFlush(batchFileDetail);
return RepeatStatus.FINISHED;
}
}
ValidateBatchFileDetailTasklet
------------------------------
@Override
public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws Exception {
BatchFileDetail batchFileDetail = batchFileDetailRepository.getRecentFailedTransactionStatus(StringConstants.FILE_NAME);
if(StringConstants.FAILED.equals(batchFileDetail.getStatus())) {
throw new BatchServiceException(batchFileDetail.getReason());
}
return RepeatStatus.FINISHED;
}
使用此解决方案,第一个错误 table 更新失败状态和失败原因,然后一步提交事务。在下一步中,根据文件名获取最近的记录并检查获取的记录的状态。如果是 FAILED
,则抛出异常以终止当前作业。
如果状态不仅仅是FAILED
,则必须处理下一个数据。如果状态为 FAILED
,我们必须终止当前批处理作业。
我配置了读取和验证数据的步骤。如果任何验证失败,我将错误 [=18=](创建以跟踪文件详细信息)状态更新为失败,并将原因更新为验证消息(BatchFileDetail 在下面的代码中为错误 table)。 一旦将其保存在数据库中,我立即根据错误 table 状态
抛出异常下面是我的代码
@Bean
public Job fileParserJob() {
return jobBuilderFactory.get("fileParserJob")
.incrementer(new RunIdIncrementer())
.start(validateFileStep())
.build();
}
public Step validateFileStep() {
return stepBuilderFactory.get("validateFileStep")
.tasklet(fileTasklet)
.build();
}
@Override
@Transactional(dontRollbackOn=BatchServiceException.class)
public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws
Exception {
Resource resource = new FileSystemResource(filePath);
BatchFileDetail batchFileDetail = new BatchFileDetail();
batchFileDetail.setFileId(String.valueOf(System.currentTimeMillis()));
batchFileDetail.setFileName(resource.getFilename());
batchFileDetail.setStatus("STARTED");
batchFileDetail.setProcessedOn(new Date());
CommonUtillity.validateBatchResource(resource, StringConstants.FILE_NAME, batchFileDetail);
validateBatchFileDetail(resource.getFile(), batchFileDetail);
batchFileDetailRepository.saveAndFlush(batchFileDetail);
if(CBOSConstants.FAILED.equals(batchFileDetail.getStatus())) {
throw new BatchServiceException(batchFileDetail.getReason());
}
return RepeatStatus.FINISHED;
}
}
但是我在错误 table 中保存的数据正在回滚。处理异常会导致继续执行另一个步骤,但我想终止当前作业并输入错误 table。 任何帮助表示赞赏。
您正在使用 @Transactional(dontRollbackOn=BatchServiceException.class)
注释您的 tasklet。这不是告诉 Spring Batch 不回滚给定异常类型的事务的方法。
您的 tasklet 将在由 Spring 批处理控制的事务范围内执行,您可以通过事务属性自定义批处理,请参阅 AbstractTaskletStepBuilder#transactionAttribute。
所以在你的情况下,你应该能够通过删除 tasklet 上的 @Transactional
来实现你的要求,并用类似的东西定义你的步骤:
@Bean
public Step validateFileStep() {
TransactionAttribute transactionAttributes = new DefaultTransactionAttribute() {
@Override
public boolean rollbackOn(Throwable exception) {
return !(exception instanceof BatchServiceException);
}
};
return stepBuilderFactory.get("validateFileStep")
.tasklet(fileTasklet)
.transactionAttribute(transactionAttributes)
.build();
}
这是一个简单的 tasklet。对于面向块的 tasklet,可以使用 FaultTolerantStepBuilder#noRollback(Class).
我找到的解决方案可能不是最好的,但根据目前的情况,我会继续进行以下操作。
@Bean
public Job fileParserJob() {
return jobBuilderFactory.get("fileParserJob")
.incrementer(new RunIdIncrementer())
.start(validateFileStep())
.next(validateFileStatusStep())
.build();
}
public Step validateFileStep() {
return stepBuilderFactory.get("validateFileStep")
.tasklet(fileTasklet)
.build();
}
public Step validateFileStatusStep() {
return stepBuilderFactory.get("validateFileStatusStep")
.tasklet(validateBatchFileDetailTasklet)
.build();
}
FileTasklet.java
-----------------
@Override
@Transactional(dontRollbackOn=BatchServiceException.class)
public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws Exception {
Resource resource = new FileSystemResource(filePath);
BatchFileDetail batchFileDetail = new BatchFileDetail();
batchFileDetail.setFileId(String.valueOf(System.currentTimeMillis()));
batchFileDetail.setFileName(resource.getFilename());
batchFileDetail.setStatus("STARTED");
batchFileDetail.setProcessedOn(new Date());
CommonUtillity.validateBatchResource(resource, StringConstants.FILE_NAME, batchFileDetail);
validateBatchFileDetail(resource.getFile(), batchFileDetail);
batchFileDetailRepository.saveAndFlush(batchFileDetail);
return RepeatStatus.FINISHED;
}
}
ValidateBatchFileDetailTasklet
------------------------------
@Override
public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws Exception {
BatchFileDetail batchFileDetail = batchFileDetailRepository.getRecentFailedTransactionStatus(StringConstants.FILE_NAME);
if(StringConstants.FAILED.equals(batchFileDetail.getStatus())) {
throw new BatchServiceException(batchFileDetail.getReason());
}
return RepeatStatus.FINISHED;
}
使用此解决方案,第一个错误 table 更新失败状态和失败原因,然后一步提交事务。在下一步中,根据文件名获取最近的记录并检查获取的记录的状态。如果是 FAILED
,则抛出异常以终止当前作业。
如果状态不仅仅是FAILED
,则必须处理下一个数据。如果状态为 FAILED
,我们必须终止当前批处理作业。