Cannot catch exception in spring batch's ItemWriter

谁说胖子不能爱 提交于 2021-02-07 09:32:46

问题


I'm writing a Spring Batch process to migrate a dataset from one system into another. In this case this is as simple as using a RowMapper implementation to build the object from a query before handing off to the ItemWriter. The ItemWriter calls the save method on my DAO (defined as an interface and handled by spring data)

The issue is this: I have a unique constraint on the MyItem table, and therefore saving a duplicated record will result in a DataIntegrityViolationException. I have tried catching this within the ItemWriter to allow me to log that a record was not imported, however during execution it never enters this catch statement. I have attempted catching Exception AND Throwable to no avail too.

From what I've noticed, there is a @Transactional annotation on the 'save' method of my DAO where I would expect the commit and flush to occur. Does Spring Batch alter this transaction in any way? Such that the @Transactional annotation applies to the 'write' method of the ItemWriter?

Can I even catch the exception in this class?

I've provided code snippets below, if you need further information - please let me know.

Many thanks for any help you can provide

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 configuration

<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>

回答1:


A couple points here:

  1. Remove the @Transactional annotation on your DAO. @Transactional and Spring Batch typically don't play nice. Spring Batch manages the transactions as part of the framework's functionality and attempting to manipulate that functionality can cause unexpected side effects.
  2. As M. Deinum points out, your ItemWriter and therefore your DAO is participating in a transaction that Spring Batch is managing. Because of this, you won't get that exception until the transaction commits.

With the above considerations in place, you have two options:

  1. You can configure skip logic to skip records that throw that exception. If you need to log the item, you can add a SkipListener to the mix so that you can log the item that caused the exception. However, there is a performance penalty to be paid with this approach since throwing the exception will result in the transaction being rolled back and replayed one item at a time.
  2. You can filter the items via an ItemProcessor. This saves the performance hit for skip logic.

You can read more about Spring Batch's skip logic in section 5.1.5 here: http://docs.spring.io/spring-batch/trunk/reference/html/configureStep.html



来源:https://stackoverflow.com/questions/29146209/cannot-catch-exception-in-spring-batchs-itemwriter

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!