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