无法在 spring 批次的 ItemWriter 中捕获异常
Cannot catch exception in spring batch's ItemWriter
我正在编写一个 Spring 批处理过程以将数据集从一个系统迁移到另一个系统。在这种情况下,这就像在传递给 ItemWriter
之前使用 RowMapper
实现从查询构建对象一样简单。 ItemWriter
在我的 DAO 上调用 save
方法(定义为接口并由 spring 数据处理)
问题是这样的:我对 MyItem table 有唯一约束,因此保存重复的记录将导致 DataIntegrityViolationException
。我已经尝试在 ItemWriter
中捕获它以允许我记录未导入的记录,但是在执行期间它永远不会进入此 catch 语句。我也尝试捕捉 Exception
和 Throwable
也无济于事。
据我所知,我的 DAO 的 'save' 方法上有一个 @Transactional
注释,我希望在该方法中发生提交和刷新。 Spring Batch 是否以任何方式更改此交易?这样 @Transactional
注释适用于 ItemWriter
?
的 'write' 方法
我什至可以在这个 class 中捕获异常吗?
我在下面提供了代码片段,如果您需要更多信息 - 请告诉我。
非常感谢您提供的任何帮助
ItemWriter
@Component
public class MyItemWriter implements ItemWriter<MyItem> {
private static final Logger LOG = LoggerFactory.getLogger(MyItemWriter.class);
@Resource
private MyItemDao myItemDao;
@Override
public void write(List<? extends MyItem> myItems) throws Exception {
for (MyItem myItem : myItems) {
try {
myItemDao.save(myItem);
} catch (Throwable ex) {
LOG.warn("Failed to import MyItem: {}: {} ", myItem.getId(), ex.toString());
}
}
}
}
DAO
public interface MyItemDao extends PagingAndSortingRepository<MyItem, Integer> {
[Custom methods omitted]
}
Spring批量配置
<batch:job id="myImportJob" restartable="true" job-repository="jobRepository">
<batch:step id="myImportStep" allow-start-if-complete="true">
<batch:tasklet>
<batch:chunk reader="myItemReader" writer="myItemWriter" commit-interval="50" />
</batch:tasklet>
</batch:step>
</batch:job>
这里有几点:
- 删除 DAO 上的
@Transactional
注释。 @Transactional
和 Spring 批处理通常效果不佳。 Spring 批处理将事务作为框架功能的一部分进行管理,尝试操纵该功能可能会导致意外的副作用。
- 正如 M. Deinum 指出的那样,您的
ItemWriter
以及您的 DAO 正在参与 Spring Batch 管理的交易。因此,在事务提交之前您不会得到该异常。
有了以上考虑,您有两个选择:
- 您可以配置跳过逻辑以跳过引发该异常的记录。如果您需要记录该项目,您可以添加一个
SkipListener
到组合中,以便您可以记录导致异常的项目。但是,这种方法会带来性能损失,因为抛出异常将导致事务回滚并一次重放一项。
- 您可以通过
ItemProcessor
过滤项目。这节省了跳过逻辑的性能损失。
您可以在此处阅读第 5.1.5 节中有关 Spring 批处理跳过逻辑的更多信息:http://docs.spring.io/spring-batch/trunk/reference/html/configureStep.html
我正在编写一个 Spring 批处理过程以将数据集从一个系统迁移到另一个系统。在这种情况下,这就像在传递给 ItemWriter
之前使用 RowMapper
实现从查询构建对象一样简单。 ItemWriter
在我的 DAO 上调用 save
方法(定义为接口并由 spring 数据处理)
问题是这样的:我对 MyItem table 有唯一约束,因此保存重复的记录将导致 DataIntegrityViolationException
。我已经尝试在 ItemWriter
中捕获它以允许我记录未导入的记录,但是在执行期间它永远不会进入此 catch 语句。我也尝试捕捉 Exception
和 Throwable
也无济于事。
据我所知,我的 DAO 的 'save' 方法上有一个 @Transactional
注释,我希望在该方法中发生提交和刷新。 Spring Batch 是否以任何方式更改此交易?这样 @Transactional
注释适用于 ItemWriter
?
我什至可以在这个 class 中捕获异常吗?
我在下面提供了代码片段,如果您需要更多信息 - 请告诉我。
非常感谢您提供的任何帮助
ItemWriter
@Component
public class MyItemWriter implements ItemWriter<MyItem> {
private static final Logger LOG = LoggerFactory.getLogger(MyItemWriter.class);
@Resource
private MyItemDao myItemDao;
@Override
public void write(List<? extends MyItem> myItems) throws Exception {
for (MyItem myItem : myItems) {
try {
myItemDao.save(myItem);
} catch (Throwable ex) {
LOG.warn("Failed to import MyItem: {}: {} ", myItem.getId(), ex.toString());
}
}
}
}
DAO
public interface MyItemDao extends PagingAndSortingRepository<MyItem, Integer> {
[Custom methods omitted]
}
Spring批量配置
<batch:job id="myImportJob" restartable="true" job-repository="jobRepository">
<batch:step id="myImportStep" allow-start-if-complete="true">
<batch:tasklet>
<batch:chunk reader="myItemReader" writer="myItemWriter" commit-interval="50" />
</batch:tasklet>
</batch:step>
</batch:job>
这里有几点:
- 删除 DAO 上的
@Transactional
注释。@Transactional
和 Spring 批处理通常效果不佳。 Spring 批处理将事务作为框架功能的一部分进行管理,尝试操纵该功能可能会导致意外的副作用。 - 正如 M. Deinum 指出的那样,您的
ItemWriter
以及您的 DAO 正在参与 Spring Batch 管理的交易。因此,在事务提交之前您不会得到该异常。
有了以上考虑,您有两个选择:
- 您可以配置跳过逻辑以跳过引发该异常的记录。如果您需要记录该项目,您可以添加一个
SkipListener
到组合中,以便您可以记录导致异常的项目。但是,这种方法会带来性能损失,因为抛出异常将导致事务回滚并一次重放一项。 - 您可以通过
ItemProcessor
过滤项目。这节省了跳过逻辑的性能损失。
您可以在此处阅读第 5.1.5 节中有关 Spring 批处理跳过逻辑的更多信息:http://docs.spring.io/spring-batch/trunk/reference/html/configureStep.html