当前位置: 首页 > 知识库问答 >
问题:

如何覆盖Spring批处理CompositeItemWriter为委托编写器管理事务,以防出现异常?

惠诚
2023-03-14

我正在扩展这个Spring批处理CompositeItemWriter如何为委托编写器管理事务?这里的问题:

在我的例子中,下面有一个compositeItemWriter,它将数据写入同一个数据库的多个表中,在写入数据之前,它通过实现各种业务规则来转换数据。在这里,一个记录可能满足不同的业务规则等,因此一个编写器可能获得比其他编写器更多的数据。

@Bean
public CompositeItemWriter<Employee> EmployeeCompositeWriter() throws Exception {
    List<ItemWriter<? super Employee>> employee = new ArrayList<>();
    employee.add(employeeWriter());
    employee.add(departmentWriter());
    employee.add(stockWriter());
    employee.add(purchaseWriter());

    CompositeItemWriter<Employee> compositeItemWriter = new CompositeItemWriter<>();
    compositeItemWriter.setDelegates(employee);
    compositeItemWriter.afterPropertiesSet();
    return compositeItemWriter;
}

场景-假设第一个writer工作得很好,第二个writer生成异常,然后第三个和第四个writer没有被调用这是automic性质在Spring批处理中默认的由于事务回滚而发生的事情。

在这里,即使第二个writer出现任何异常,我要成功调用第三个和第四个writer并保存数据,我也要成功保存第一个writer和第二个writer的数据。在skiplistener的帮助下,我只想将异常数据存储到错误表中,以识别哪些记录是垃圾或垃圾。

html" target="_blank">解决方案--为了实现上述场景,我们在每个writer写入方法上添加了@transactional(propagation=propagation.requires_new),第一个writer现在保存了数据,第二个writer生成了异常(使用名为JDBCTemplate.BatchUpdate()批量更新数据),我们缓存它并重新抛出它,但是我们可以看到提交级别被降低到1(偏离了识别extact垃圾记录的过程),并且第二个writer再次出现了moment异常。第一个writer被调用,它保存了重复的数据,第二个、第三个和第四个writer被调用,但是垃圾记录没有流向第三个和第四个writer。

在这里,如果单个或两个记录是垃圾,我不希望整个批处理作业停止,因为这个作业对于我们每次运行都是至关重要的。是否有任何方法,如果我们可以保存所有的数据,在不出现异常的地方,并且只有在skiplistener的帮助下保存异常数据到错误表中(如果可能的话),或者其他任何方法?

是否有任何方法,如果我们可以重用批处理组件,如(读取器或处理器)的任何步骤的一部分到另一个步骤?

共有1个答案

郁宾鸿
2023-03-14

我看不出有什么方法可以将Spring-Batch的单个事务与将原子性保留给单独的编写器(只要您想要skiplistener即可)对齐,以便将整个块编写为原子。

我不确定这是否可能,但可能是,你将能够测试它很快。这就是在一些集成框架(如camel)中消息如何将异常从一个处理器传送到错误处理流的方式。

>

  • 项目阅读器应返回一个EmployeeWrapper,它包含Employee记录,并具有一个存储异常的字段。

        List<ItemWriter<? super EmployeeWrapper>> employee = new ArrayList<>();
        employee.add(employeeWriter());
        employee.add(departmentWriter());
        employee.add(stockWriter());
        employee.add(purchaseWriter());
        employee.add(errorRecordWriter());
    

    >

  • 您的前4个单独编写器从不抛出异常,而是将其标记为已处理,但将捕获的异常添加为EmployeeWrapper的属性。

    第5个errorRecordWriter接收所有记录,检查添加了异常属性的任何记录,并将它们写入错误表。如果它无法写入错误记录,您可以抛出异常,所有5个写入程序将被重试。

    关于在批处理更新失败时如何知道哪个记录是错误记录。似乎当chunk中出现错误时,spring会回滚该chunk并开始在该chunk中逐条记录重试,这样它就知道哪个记录是有问题的。所以你可以在你的个人作家中做同样的事情。即捕获批处理更新异常,然后逐个重试以分离错误记录

  •  类似资料:
    • 关于文章Spring批处理CompositeItemWriter如何管理委托编写器的事务?,对于复合项编写器事务管理,难道不应该将数据源包装在如下所示的事务管理器中吗?没有下面的bean定义,事务管理就无法与Oracle和Hikari CP一起工作。不确定帖子中提供的示例是如何工作的。请澄清

    • 我使用spring批处理从数据库中读取数据(使用分区),并根据输入键-1,2,3,4将数据写入一组文件。 我创建了一个CompositeItemWriter,它是两个ClassifierCompositeItemWriter的组合。即使我已将单个Writer注册为stream,但仍然会遇到以下异常: 我甚至尝试将ItemWriter1和ItemWriter2注册为流,但这给了我一个不同的错误: 请

    • 我目前有以下spring批处理(v2.2.4)作业,它从单个数据源读取,然后创建三种不同的输出格式。我有三个步骤,每个步骤都有一个标准的读取器、处理器和写入器bean。我使用下面的括号来表示每个处理器或写入器使用的格式。本例中的每个处理器都向writer bean返回一个SqlParameterSource对象。 我不喜欢这样一个事实,即我要三次读取相同的数据,所以我打算在新的工作中使用复合处理器

    • 我想了解Spring Batch是如何进行事务管理的。这不是一个技术问题,而是一个概念性的问题:Spring Batch使用什么方法?这种方法的后果是什么? 让我试着澄清一下这个问题。例如,在TaskletStep中,我看到步骤执行通常如下所示: 准备步骤元数据的几个JobRepository事务 每一块要处理的业务事务 更多JobRepository事务,用区块处理的结果更新步骤元数据 这似乎是

    • 我有一个compositeItemWriter,它有2个代理编写器:1。HeaderWriter将一些字段从我的对象写入头表2。DetailWriter将文件写入详细表。 context.xml: