Spring Batch 从两个数据库表中读取数据并写入 XML 文件
Springbatch reading data from two DB tables and write to XML file
我是 spring 批次的新手,我想就我遇到的问题获得一些指导。我有两个数据库表 Settlement_Header(其中包含文件的 header 信息)和 Settlement_Detail(这是该 header 文件的所有事务的列表。)
目标是创建一个包含 1 header 和多个详细信息的文件。
当前输出 - header 出现在每条记录上,我希望它出现一次。我试图在项目处理器中包含一个条件,但它没有解决我的问题。
Current Output
期望的输出
Desired Output
这是我的 Itemreader
@Bean(destroyMethod="")
public JdbcCursorItemReader<Settlement> settlementreader(){
JdbcCursorItemReader<Settlement> ItemReader = new JdbcCursorItemReader<>();
ItemReader.setDataSource(dataSource);
ItemReader.setSql("SELECT DISTINCT A.PROCESS_DATE,A.FILE_NAME,A.SERVICE,A.SUB_SERVICE,A.SENDER,A.RUN_MODE,A.CURRENCY,A.PROCESS_WINDOW_NO,B.RECORD_SEQ_NO,"
+ "B.AGENT_FROM,B.AGENT_TO,B.SETTLE_VOLUME,B.AMOUNT_CURRENCY,B.SETTLE_AMOUNT "
+ "FROM SETTLEMENT_HEADER A,SETTLEMENT_DETAIL B WHERE A.FILE_ID=B.FILE_ID");
ItemReader.setRowMapper(new SettlementRowMapper());
return ItemReader;
}
作家
@Bean (destroyMethod="")
public StaxEventItemWriter<Settlement> settlementwriter() throws Exception {
StaxEventItemWriter<Settlement> ItemWriter = new StaxEventItemWriter<>();
ItemWriter.setResource(new FileSystemResource(".../Settlement.xml"));
ItemWriter.setRootTagName("Settlement");
ItemWriter.setMarshaller(marshaller);
ItemWriter.afterPropertiesSet();
return ItemWriter;
}
行映射器
public class SettlementRowMapper 实现 RowMapper {
@Override
public Settlement mapRow(ResultSet rs, int rowNum) throws SQLException {
Settlement Settlement = new Settlement ();
List<SettlementHeader> settlementheader= new ArrayList<SettlementHeader>();
List<SettlementDetail> settlementdetail = new ArrayList<SettlementDetail>();
SettlementHeader header = new SettlementHeader();
SettlementDetail detail = new SettlementDetail();
SttlAmt sttlAmt = new SttlAmt();
header.setPrcDte(rs.getDate("PROCESS_DATE").toLocalDate());
header.setFilename(rs.getString("FILE_NAME"));
header.setService(rs.getString("SERVICE"));
header.setSubServ(rs.getString("SUB_SERVICE"));
header.setSender(rs.getInt("SENDER"));
header.setRunMode(rs.getString("RUN_MODE"));
header.setCurrency(rs.getString("CURRENCY"));
header.setPrcWndwNum(rs.getInt("PROCESS_WINDOW_NO"));
detail.setSeqNumb(rs.getInt("RECORD_SEQ_NO"));
detail.setAgntFrm(rs.getInt("AGENT_FROM"));
detail.setAgntTo(rs.getInt("AGENT_TO"));
detail.setSttlVol(rs.getInt("SETTLE_VOLUME"));
sttlAmt.setCcy(rs.getString("AMOUNT_CURRENCY"));
sttlAmt.setValue(rs.getDouble("SETTLE_AMOUNT"));
detail.setSttlAmt(sttlAmt);
settlementheader.add(header);
settlementdetail.add(detail);
Settlement.setSettlementDetails(settlementdetail);
Settlement.setSettlementHeader(settlementheader);
return Settlement;
}
您的行为是绝对正常的,因为对于您阅读的每个项目,您都有一个包含一个 Header 和一个细节的解决方案 object。
您的问题在批处理领域很常见,对于 Spring 批处理,它被称为 "Driving Query Based ItemReaders",您可以在
here.
我按照这种模式处理你的问题的方法是创建一个只有 returns SettlementHeader
个项目的 reader,并添加一个处理每个项目的处理器(SettlementHeader
) 并通过查询数据库中的 Settlement Details
将其转换为 Settlement Object
。
这是我的解决方案:
步骤项目
@Bean(destroyMethod = "")
public JdbcCursorItemReader<SettlementHeader> settlementHeaderReader(DataSource dataSource) {
JdbcCursorItemReader<SettlementHeader> ItemReader = new JdbcCursorItemReader<>();
ItemReader.setDataSource(dataSource);
ItemReader.setSql("SELECT DISTINCT A.FILE_ID, A.PROCESS_DATE, A.FILE_NAME, A.SERVICE, A.SUB_SERVICE, A.SENDER, A.RUN_MODE, A.CURRENCY, A.PROCESS_WINDOW_NO"
+ "FROM SETTLEMENT_HEADER A");
ItemReader.setRowMapper(new SettlementHeaderRowMapper());
return ItemReader;
}
@Bean
public ItemProcessor<SettlementHeader, Settlement> settlementHeaderProcessor(JdbcTemplate jdbcTemplate){
return item -> {
List<SettlementDetail> settlementDetails = jdbcTemplate.query("SELECT B.RECORD_SEQ_NO, B.AGENT_FROM,B.AGENT_TO,B.SETTLE_VOLUME,B.AMOUNT_CURRENCY,B.SETTLE_AMOUNT " +
" FROM SETTLEMENT_DETAIL B WHERE ? = B.FILE_ID",
new Object[]{item.getFileId()},
new SettlementDetailRowMapper());
Settlement settlement = new Settlement ();
List<SettlementHeader> settlementheader= new ArrayList<SettlementHeader>();
settlementheader.add(item);
settlement.setSettlementDetails(settlementDetails);
settlement.setSettlementHeader(settlementheader);
return settlement;
};
}
// Your writer should stay the same
@Bean(destroyMethod = "")
public StaxEventItemWriter<Settlement> settlementwriter() throws Exception {
StaxEventItemWriter<Settlement> ItemWriter = new StaxEventItemWriter<>();
ItemWriter.setResource(new FileSystemResource(".../Settlement.xml"));
ItemWriter.setRootTagName("Settlement");
ItemWriter.setMarshaller(marshaller);
ItemWriter.afterPropertiesSet();
return ItemWriter;
}
行映射器
public class SettlementHeaderRowMapper implements RowMapper<SettlementHeader> {
@Override
public SettlementHeader mapRow(ResultSet rs, int i) throws SQLException {
SettlementHeader header = new SettlementHeader();
header.setFileId(rs.getInt("FILE_ID"));
header.setPrcDte(rs.getDate("PROCESS_DATE").toLocalDate());
header.setFilename(rs.getString("FILE_NAME"));
header.setService(rs.getString("SERVICE"));
header.setSubServ(rs.getString("SUB_SERVICE"));
header.setSender(rs.getInt("SENDER"));
header.setRunMode(rs.getString("RUN_MODE"));
header.setCurrency(rs.getString("CURRENCY"));
header.setPrcWndwNum(rs.getInt("PROCESS_WINDOW_NO"));
return header;
}
}
public class SettlementDetailRowMapper implements RowMapper<SettlementDetail> {
@Override
public SettlementDetail mapRow(ResultSet rs, int i) throws SQLException {
SettlementDetail detail = new SettlementDetail();
SttlAmt sttlAmt = new SttlAmt();
detail.setSeqNumb(rs.getInt("RECORD_SEQ_NO"));
detail.setAgntFrm(rs.getInt("AGENT_FROM"));
detail.setAgntTo(rs.getInt("AGENT_TO"));
detail.setSttlVol(rs.getInt("SETTLE_VOLUME"));
sttlAmt.setCcy(rs.getString("AMOUNT_CURRENCY"));
sttlAmt.setValue(rs.getDouble("SETTLE_AMOUNT"));
detail.setSttlAmt(sttlAmt);
return detail;
}
}
希望对您有所帮助。
我是 spring 批次的新手,我想就我遇到的问题获得一些指导。我有两个数据库表 Settlement_Header(其中包含文件的 header 信息)和 Settlement_Detail(这是该 header 文件的所有事务的列表。)
目标是创建一个包含 1 header 和多个详细信息的文件。
当前输出 - header 出现在每条记录上,我希望它出现一次。我试图在项目处理器中包含一个条件,但它没有解决我的问题。
Current Output
期望的输出
Desired Output
这是我的 Itemreader
@Bean(destroyMethod="")
public JdbcCursorItemReader<Settlement> settlementreader(){
JdbcCursorItemReader<Settlement> ItemReader = new JdbcCursorItemReader<>();
ItemReader.setDataSource(dataSource);
ItemReader.setSql("SELECT DISTINCT A.PROCESS_DATE,A.FILE_NAME,A.SERVICE,A.SUB_SERVICE,A.SENDER,A.RUN_MODE,A.CURRENCY,A.PROCESS_WINDOW_NO,B.RECORD_SEQ_NO,"
+ "B.AGENT_FROM,B.AGENT_TO,B.SETTLE_VOLUME,B.AMOUNT_CURRENCY,B.SETTLE_AMOUNT "
+ "FROM SETTLEMENT_HEADER A,SETTLEMENT_DETAIL B WHERE A.FILE_ID=B.FILE_ID");
ItemReader.setRowMapper(new SettlementRowMapper());
return ItemReader;
}
作家
@Bean (destroyMethod="")
public StaxEventItemWriter<Settlement> settlementwriter() throws Exception {
StaxEventItemWriter<Settlement> ItemWriter = new StaxEventItemWriter<>();
ItemWriter.setResource(new FileSystemResource(".../Settlement.xml"));
ItemWriter.setRootTagName("Settlement");
ItemWriter.setMarshaller(marshaller);
ItemWriter.afterPropertiesSet();
return ItemWriter;
}
行映射器
public class SettlementRowMapper 实现 RowMapper {
@Override
public Settlement mapRow(ResultSet rs, int rowNum) throws SQLException {
Settlement Settlement = new Settlement ();
List<SettlementHeader> settlementheader= new ArrayList<SettlementHeader>();
List<SettlementDetail> settlementdetail = new ArrayList<SettlementDetail>();
SettlementHeader header = new SettlementHeader();
SettlementDetail detail = new SettlementDetail();
SttlAmt sttlAmt = new SttlAmt();
header.setPrcDte(rs.getDate("PROCESS_DATE").toLocalDate());
header.setFilename(rs.getString("FILE_NAME"));
header.setService(rs.getString("SERVICE"));
header.setSubServ(rs.getString("SUB_SERVICE"));
header.setSender(rs.getInt("SENDER"));
header.setRunMode(rs.getString("RUN_MODE"));
header.setCurrency(rs.getString("CURRENCY"));
header.setPrcWndwNum(rs.getInt("PROCESS_WINDOW_NO"));
detail.setSeqNumb(rs.getInt("RECORD_SEQ_NO"));
detail.setAgntFrm(rs.getInt("AGENT_FROM"));
detail.setAgntTo(rs.getInt("AGENT_TO"));
detail.setSttlVol(rs.getInt("SETTLE_VOLUME"));
sttlAmt.setCcy(rs.getString("AMOUNT_CURRENCY"));
sttlAmt.setValue(rs.getDouble("SETTLE_AMOUNT"));
detail.setSttlAmt(sttlAmt);
settlementheader.add(header);
settlementdetail.add(detail);
Settlement.setSettlementDetails(settlementdetail);
Settlement.setSettlementHeader(settlementheader);
return Settlement;
}
您的行为是绝对正常的,因为对于您阅读的每个项目,您都有一个包含一个 Header 和一个细节的解决方案 object。
您的问题在批处理领域很常见,对于 Spring 批处理,它被称为 "Driving Query Based ItemReaders",您可以在 here.
我按照这种模式处理你的问题的方法是创建一个只有 returns SettlementHeader
个项目的 reader,并添加一个处理每个项目的处理器(SettlementHeader
) 并通过查询数据库中的 Settlement Details
将其转换为 Settlement Object
。
这是我的解决方案:
步骤项目
@Bean(destroyMethod = "")
public JdbcCursorItemReader<SettlementHeader> settlementHeaderReader(DataSource dataSource) {
JdbcCursorItemReader<SettlementHeader> ItemReader = new JdbcCursorItemReader<>();
ItemReader.setDataSource(dataSource);
ItemReader.setSql("SELECT DISTINCT A.FILE_ID, A.PROCESS_DATE, A.FILE_NAME, A.SERVICE, A.SUB_SERVICE, A.SENDER, A.RUN_MODE, A.CURRENCY, A.PROCESS_WINDOW_NO"
+ "FROM SETTLEMENT_HEADER A");
ItemReader.setRowMapper(new SettlementHeaderRowMapper());
return ItemReader;
}
@Bean
public ItemProcessor<SettlementHeader, Settlement> settlementHeaderProcessor(JdbcTemplate jdbcTemplate){
return item -> {
List<SettlementDetail> settlementDetails = jdbcTemplate.query("SELECT B.RECORD_SEQ_NO, B.AGENT_FROM,B.AGENT_TO,B.SETTLE_VOLUME,B.AMOUNT_CURRENCY,B.SETTLE_AMOUNT " +
" FROM SETTLEMENT_DETAIL B WHERE ? = B.FILE_ID",
new Object[]{item.getFileId()},
new SettlementDetailRowMapper());
Settlement settlement = new Settlement ();
List<SettlementHeader> settlementheader= new ArrayList<SettlementHeader>();
settlementheader.add(item);
settlement.setSettlementDetails(settlementDetails);
settlement.setSettlementHeader(settlementheader);
return settlement;
};
}
// Your writer should stay the same
@Bean(destroyMethod = "")
public StaxEventItemWriter<Settlement> settlementwriter() throws Exception {
StaxEventItemWriter<Settlement> ItemWriter = new StaxEventItemWriter<>();
ItemWriter.setResource(new FileSystemResource(".../Settlement.xml"));
ItemWriter.setRootTagName("Settlement");
ItemWriter.setMarshaller(marshaller);
ItemWriter.afterPropertiesSet();
return ItemWriter;
}
行映射器
public class SettlementHeaderRowMapper implements RowMapper<SettlementHeader> {
@Override
public SettlementHeader mapRow(ResultSet rs, int i) throws SQLException {
SettlementHeader header = new SettlementHeader();
header.setFileId(rs.getInt("FILE_ID"));
header.setPrcDte(rs.getDate("PROCESS_DATE").toLocalDate());
header.setFilename(rs.getString("FILE_NAME"));
header.setService(rs.getString("SERVICE"));
header.setSubServ(rs.getString("SUB_SERVICE"));
header.setSender(rs.getInt("SENDER"));
header.setRunMode(rs.getString("RUN_MODE"));
header.setCurrency(rs.getString("CURRENCY"));
header.setPrcWndwNum(rs.getInt("PROCESS_WINDOW_NO"));
return header;
}
}
public class SettlementDetailRowMapper implements RowMapper<SettlementDetail> {
@Override
public SettlementDetail mapRow(ResultSet rs, int i) throws SQLException {
SettlementDetail detail = new SettlementDetail();
SttlAmt sttlAmt = new SttlAmt();
detail.setSeqNumb(rs.getInt("RECORD_SEQ_NO"));
detail.setAgntFrm(rs.getInt("AGENT_FROM"));
detail.setAgntTo(rs.getInt("AGENT_TO"));
detail.setSttlVol(rs.getInt("SETTLE_VOLUME"));
sttlAmt.setCcy(rs.getString("AMOUNT_CURRENCY"));
sttlAmt.setValue(rs.getDouble("SETTLE_AMOUNT"));
detail.setSttlAmt(sttlAmt);
return detail;
}
}
希望对您有所帮助。