Java Spring批处理-通过提取自动生成的键写入两个表

Java Spring批处理-通过提取自动生成的键写入两个表,java,spring,spring-batch,Java,Spring,Spring Batch,使用SpringBatch时,我需要将数据写入两个不同的表。似乎我可以将一个复合ItemWriter与尽可能多的ItemWriter一起使用 但是,我需要在第一个表中插入一条记录,检索自动生成的主键,并在插入第二个表时使用它。 知道在这种情况下如何检索自动生成的密钥吗?写入程序总是按顺序执行。因此,您可以在第一个writer中写入第一个表并读取生成的键,然后在第二个writer中写入第二个表。如果您在第一个写入程序中更新了对象,那么您将在第二个写入程序中得到更新 第一个作者可能看起来像: pub

使用SpringBatch时,我需要将数据写入两个不同的表。似乎我可以将一个
复合ItemWriter
与尽可能多的
ItemWriter
一起使用

但是,我需要在第一个表中插入一条记录,检索自动生成的主键,并在插入第二个表时使用它。
知道在这种情况下如何检索自动生成的密钥吗?

写入程序总是按顺序执行。因此,您可以在第一个writer中写入第一个表并读取生成的键,然后在第二个writer中写入第二个表。如果您在第一个写入程序中更新了对象,那么您将在第二个写入程序中得到更新

第一个作者可能看起来像:

public class MyWriter implements ItemWriter<MyObject> {
    @Override
    public void write(List<? extends MyObject> items) throws Exception {
        // assuming there is a DB connection
        for(MyObject item: items) {
            // create and execute query to insert data in table 1
            // get generated key and assign it into object
            int key = rs.getInt(...);
            item.setGeneratedKey(key);
        }
    }
}
公共类MyWriter实现ItemWriter{
@凌驾

public void write(ListWis)解决方案确实有效,但从您的性能角度来看(这通常是讨论批处理时的主要关注点之一),不建议使用该解决方案

问题: 如何选择插入的行以读取生成的键? 您是否有另一个唯一的字段,或者至少是它的组合,可以让您识别所有已写入的项目? 您能否将“项目”列表中的至少所有项目作为对 db或您必须用自己的select读取每个条目吗

至少,您将有一个对db的额外读取调用。但它也可能是每个项的额外调用

更好的解决方案是能够在批处理中创建密钥

如果我们只讨论几千次插入,性能可能不是问题。但是,如果我们讨论数百万次插入,它将很重要

无论如何,如果我真的必须重新读取数据库,我将使用以下两种方法

首先,如果我不必在同一事务中写入两个表

第一步:

  • 从源代码中读取
  • 准备数据
  • 写入创建数据的表1
第二步:

  • 使用生成的id从表1中读取
  • 如有必要,进行一些处理
  • 写入表2
第二,如果我必须在同一事务中写入两个表

公共类MyWriter实现ItemWriter{
私有JdbcItemWriter编写器1;
私有JdbcItemWriter编写器2;
@施工后
公共无效afterPropertiesSet(){
writer1=新的JdbcItemWriter();
writer1.set。。。
writer1.afterPropertieSet();
writer2=…同样的事情
}
公共无效写入(列表项){
书写者1.书写(项目);
列表重读项=
新JdbcTemplate(数据源)
//您可以使用具有唯一区块id的行
//或者,您可以使用适当的
//在子句中…但是,在子句中可能出现的
//是有限的,例如oracle有1000个
.query(仅选择您在上面插入的条目的查询,
(结果集,行)->//行映射器
{ 
MyObject obj=新的MyObject();
对象setXy(resultset.get…);
...
返回obj;
});
writer2.写入(重新读取项);
}
}

这至少会将您对db的调用限制为每个数据块添加一个调用。

我对Spring批处理启动很陌生。但我有很多大型机批处理经验。我会这样做,假设您有输入文件: 1-使作业仅插入具有生成键的实体A 2-制作作业(或步骤),通过读取db来使用生成的键扩展输入。输出=输入+生成的键 3-使工作符合您的实体B
因此,不要试图一步到位….

谢谢,将区块id存储为列并将其用于第二个表是个好主意。Thx Hansjoerg指出了我的解决方案的弱点。事实上,我的代码不是逐个读取生成的键,而是每个区块一个查询。我的代码相当复杂,我确实想简化。但我完全同意应该实现块读取。
public class MyWriter implements ItemWriter<MyObject> {
    private JdbcItemWriter<MyObject> writer1;
    private JdbcItemWriter<MyObject> writer2;

    @PostConstruct
    public void afterPropertiesSet() {
         writer1 = new JdbcItemWriter<MyObject>();
         writer1.set...
         writer1.afterPropertiesSet();

         writer2 = ... same thing

    }

    public void write(List<MyObject> items) {
         writer1.write(items);

         List<MyObject> reReadItems = 
                new JdbcTemplate(datasource)
                   // you could use a row that which has a unique chunk id
                   // or you could construct a query with an appropriate
                   // in-Clause... however, the size of possible in-clauses
                   // is limited, for instance oracle has 1000
                   .query(a query that selects only the entries you inserted above,
                (resultset, row) -> // RowMapper
                { 
                    MyObject obj = new MyObject();
                    obj.setXy(resultset.get...);
                    ...
                    return obj;
                 });
          writer2.write(reReadItems);
    }
}