Spring 批处理 - 有没有办法在块引发异常时提交数据?
Spring Batch - Is there a way to commit data even if the chunk raise some exception?
我有一个从队列读取、处理并写入数据库的进程。即使过程失败,我也必须存储在数据库中。但是 Spring 批处理步骤是事务性的,并且总是回滚更改。那么,有没有一种方法可以在块引发异常的情况下提交数据?
编辑我:
我尝试使用 Tasklet 但得到了相同的行为。
提前致谢。
即使在处理过程中出现异常时,您也可以编写 JOB 来提交所有数据的一种方法是使用 SkipPolicy 并将数据写入那里的目标数据库。
SkipPolicy 的主要好处之一是通过处理记录导致异常的数据,记录部分甚至可以将记录插入临时 Table 在您的数据库中。
public class FileVerificationSkipper implements SkipPolicy {
private static final int MAX_VALUES_TO_SKIP = 1000;
private JdbcTemplate jdbcTemplate;
public FileVerificationSkipper(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
}
@Override
public boolean shouldSkip(Throwable exception, int skipCount) throws SkipLimitExceededException {
if (exception instanceof FlatFileParseException && skipCount <= MAX_VALUES_TO_SKIP) {
jdbcTemplate.update("INSERT INTO YourTable(column1, column2) VALUES(?,?)");
return true;
} else {
return false;
}
}
}
希望对您有所帮助。
在配置步骤时,可以使用noRollback()
配置不会回滚的异常列表。作为已配置异常的子类的任何异常都不会回滚。这意味着如果您只是想永不回滚,请将其设置为 Exception
这是所有异常的父级。
可以从 docs 中找到示例:
@Bean
public Step step1() {
return this.stepBuilderFactory.get("step1")
.<String, String>chunk(2)
.reader(itemReader())
.writer(itemWriter())
.faultTolerant()
.noRollback(Exception.class)
.build();
}
我尝试按照 Ken Chan 的建议使用 noRollback()
,但没有用。也尝试把特定的例外,但它一直在做 rololback。
条件流程处于步骤级别而非项目级别,因此对我没有帮助。还尝试使用 Listeners,但文档说:
This listener is designed to work around the lifecycle of an item. This means that each method should be called once within the lifecycle of an item and in fault tolerant scenarios, any transactional work that is done in one of these methods would be rolled back and not re-applied. Because of this, it is recommended to not perform any logic using this listener that participates in a transaction.
我使用 Tasklet 解决了我的问题,而不是面向分块的解决方案,并将 @Transactional 添加到 Tasklet 的执行方法。
@Transactional(propagation = Propagation.REQUIRES_NEW, isolation = Isolation.SERIALIZABLE, noRollbackFor = {
ErrorInternoServidorException.class, SolicitudIncorrectaException.class,
RegistroNoEncontradoException.class, SolicitudEventoObjetaException.class,
SolicitudEventoValidaException.class, MimCargueSolicitudException.class, ConflictException.class,
UnauthorizedException.class, ForbiddenException.class })
public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws Exception {
Spring Batch chunked oriented解决方案被包装在一个Tasklet中,有他自己的事务,所以我试着用我自己的规则创建一个新的。
感谢大家的回复。我学到了很多。
我有一个从队列读取、处理并写入数据库的进程。即使过程失败,我也必须存储在数据库中。但是 Spring 批处理步骤是事务性的,并且总是回滚更改。那么,有没有一种方法可以在块引发异常的情况下提交数据?
编辑我:
我尝试使用 Tasklet 但得到了相同的行为。
提前致谢。
即使在处理过程中出现异常时,您也可以编写 JOB 来提交所有数据的一种方法是使用 SkipPolicy 并将数据写入那里的目标数据库。
SkipPolicy 的主要好处之一是通过处理记录导致异常的数据,记录部分甚至可以将记录插入临时 Table 在您的数据库中。
public class FileVerificationSkipper implements SkipPolicy {
private static final int MAX_VALUES_TO_SKIP = 1000;
private JdbcTemplate jdbcTemplate;
public FileVerificationSkipper(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
}
@Override
public boolean shouldSkip(Throwable exception, int skipCount) throws SkipLimitExceededException {
if (exception instanceof FlatFileParseException && skipCount <= MAX_VALUES_TO_SKIP) {
jdbcTemplate.update("INSERT INTO YourTable(column1, column2) VALUES(?,?)");
return true;
} else {
return false;
}
}
}
希望对您有所帮助。
在配置步骤时,可以使用noRollback()
配置不会回滚的异常列表。作为已配置异常的子类的任何异常都不会回滚。这意味着如果您只是想永不回滚,请将其设置为 Exception
这是所有异常的父级。
可以从 docs 中找到示例:
@Bean
public Step step1() {
return this.stepBuilderFactory.get("step1")
.<String, String>chunk(2)
.reader(itemReader())
.writer(itemWriter())
.faultTolerant()
.noRollback(Exception.class)
.build();
}
我尝试按照 Ken Chan 的建议使用 noRollback()
,但没有用。也尝试把特定的例外,但它一直在做 rololback。
条件流程处于步骤级别而非项目级别,因此对我没有帮助。还尝试使用 Listeners,但文档说:
This listener is designed to work around the lifecycle of an item. This means that each method should be called once within the lifecycle of an item and in fault tolerant scenarios, any transactional work that is done in one of these methods would be rolled back and not re-applied. Because of this, it is recommended to not perform any logic using this listener that participates in a transaction.
我使用 Tasklet 解决了我的问题,而不是面向分块的解决方案,并将 @Transactional 添加到 Tasklet 的执行方法。
@Transactional(propagation = Propagation.REQUIRES_NEW, isolation = Isolation.SERIALIZABLE, noRollbackFor = {
ErrorInternoServidorException.class, SolicitudIncorrectaException.class,
RegistroNoEncontradoException.class, SolicitudEventoObjetaException.class,
SolicitudEventoValidaException.class, MimCargueSolicitudException.class, ConflictException.class,
UnauthorizedException.class, ForbiddenException.class })
public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws Exception {
Spring Batch chunked oriented解决方案被包装在一个Tasklet中,有他自己的事务,所以我试着用我自己的规则创建一个新的。
感谢大家的回复。我学到了很多。