我正在尝试为批处理创建一个简单的步骤,该步骤从项目处理器获取 ProductDetail 信息和其他信息来创建新的 ProductResult 并将其写入 Mongodb 数据库。我正在尝试使用 JdbcPagingItemReader 从数据库读取数据。但是,当我开始工作时,它失败并出现错误
java.lang.NullPointerException: Cannot invoke "org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate.getJdbcOperations()" because "this.namedParameterJdbcTemplate" is null.
我还用另一个阅读器测试了它,它可以工作,所以这只是 JdbcPagingItemReader 的问题。
我不知道为什么需要 NamedParameterJdbcTemplate,因为我已经提供了 select 和 from 值以及配置的行映射器。
这是我的代码
import com.datacom.mapper.ProductDetailRowMapper;
import com.datacom.model.ProductDetail;
import lombok.RequiredArgsConstructor;
import org.springframework.batch.core.Step;
import org.springframework.batch.core.repository.JobRepository;
import org.springframework.batch.core.step.builder.StepBuilder;
import org.springframework.batch.item.ItemStreamReader;
import org.springframework.batch.item.ItemWriter;
import org.springframework.batch.item.data.MongoItemWriter;
import org.springframework.batch.item.data.builder.MongoItemWriterBuilder;
import org.springframework.batch.item.database.JdbcPagingItemReader;
import org.springframework.batch.item.database.Order;
import org.springframework.batch.item.database.support.OraclePagingQueryProvider;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.mongodb.core.MongoOperations;
import org.springframework.transaction.PlatformTransactionManager;
import javax.sql.DataSource;
import java.util.HashMap;
import java.util.Map;
@Configuration
@RequiredArgsConstructor
public class ProductDetailConfigStep {
@Value("${db.pageSize}")
int pageSize;
final MongoOperations mongoOperations;
final @Qualifier("productsDataSource") DataSource dataSource;
final PlatformTransactionManager transactionManager;
final JobRepository jobRepository;
@Value("${batch.chunkSize}") int chunkSize;
final ProductResultProcessor productResultProcessor;
public ItemStreamReader<ProductDetail> itemReader() {
JdbcPagingItemReader<ProductDetail> itemReader = new JdbcPagingItemReader<>();
itemReader.setDataSource(productsDataSource);
itemReader.setFetchSize(chunkSize);
OraclePagingQueryProvider queryProvider = new OraclePagingQueryProvider();
queryProvider.setSelectClause(JDBCConstants.SELECT_QUERY);
queryProvider.setFromClause(JDBCConstants.FROM_CLAUSE_QUERY);
itemReader.setRowMapper(new ProductDetailRowMapper());
final Map<String, Order> sortKeys = new HashMap<>();
itemReader.setParameterValues(new HashMap<>());
sortKeys.put("product_id", Order.ASCENDING);
queryProvider.setSortKeys(sortKeys);
itemReader.setQueryProvider(queryProvider);
itemReader.setPageSize(pageSize);
itemReader.setPageSize(chunkSize);
return itemReader;
}
public ItemWriter<ProductResult> itemWriter() {
var writer = new MongoItemWriterBuilder<ProductResult>()
.collection(Documents.PRODUCT_CATALOG_COLLECTION)
.mode(MongoItemWriter.Mode.INSERT)
.template(mongoOperations)
.build();
writer.setTemplate(mongoOperations);
return writer;
}
@Bean("productProcessingDetailStep")
public Step productProcessingDetailStep() {
return new StepBuilder("productCreationStep", jobRepository)
.<ProductDetail, ProductResult>chunk(chunkSize, transactionManager)
.reader(itemReader())
.processor(productResultProcessor)
.writer(itemWriter())
.build();
}
}
我缺少什么 JdbcPagingItemReader 的配置对我来说看起来很好。
字段
namedParameterJdbcTemplate
是null
,因为读者的方法afterProperties
没有被调用。
如果你将 reader 作为 bean 公开,那么 Spring 会为你调用这个方法。但如果读者没有其他需要的话,你也可以自己做。
如果您像这样更改代码,它应该按预期工作:
public ItemStreamReader<ProductDetail> itemReader() throws Exception {
...
itemReader.afterPropertiesSet();
return itemReader;
}
请注意方法签名中的
throws Exception
。或者,您可以将对 afterPropertiesSet
的调用包装在适当的 try-catch 块中。