Spring批处理 - 通过提取自动生成的密钥

时间:2017-03-23 11:21:36

标签: java spring spring-batch

使用spring批处理时,我需要将数据写入两个不同的表。看起来我可以使用尽可能多CompositeItemWriter的{​​{1}}。

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

3 个答案:

答案 0 :(得分:4)

威斯康星州'解决方案确实有效,但从您的性能角度来看(通常是讨论批处理时的主要问题之一),不推荐使用。

问题: 如何选择插入的行以读取生成的键? 你有另一个独特的领域,或者至少是它的组合,它可以让你识别书面项目? 你能把至少所有项目列表中的所有项目都读作一个单独的来电 db或者您是否必须使用自己的select?

读取每个条目

至少,您将对数据库进行额外的读取调用。但它也可以是每个项目的额外电话。

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

如果我们只讨论几千个插页,性能可能不是问题。但是,如果我们谈论数百万,那就很重要。

无论如何,如果我真的不得不重新阅读db,我会使用以下两种方法。

首先,如果我不必在同一个交易中写两个表

第1步:

  • 从源头阅读
  • 准备数据
  • 写入表1,创建数据

第2步:

  • 从表1中读取生成的ID
  • 必要时进行一些处理
  • 写信给表2

其次,如果我必须在同一个事务中写两个表

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);
    }
}

这至少会限制你对数据库的调用,每个块的一次加法调用。

答案 1 :(得分:1)

编写器总是按顺序执行。因此,您可以写入第一个表并在第一个写入器中读取生成的键,并写入第二个写入器中的第二个表。如果您更新了第一个编写器中的对象,您将在第二个编写器中获得更新。

第一位作家可能看起来像:

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);
        }
    }
}

第二个编写者可以使用generatedKey字段来构造表2的查询。当您在第一个编写器中注入该值时,它将可供第二个编写者使用。

答案 2 :(得分:0)

我是Springby批量启动的新人。但是有很多大型机批处理经验。假设您已输入文件,我将以这种方式进行操作: 1-制作仅插入具有生成键的实体A的作业 2-制作作业(或步骤),以通过读取db扩展带有生成键的输入。输出=输入+生成的密钥 3-做插入你的实体B的工作 因此,请勿尝试一步之遥.....