You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

JdbcPagingItemReader配置Step时因NamedParameterJdbcTemplate为空报错

Spring Batch JdbcPagingItemReader 空指针问题排查

问题描述

我正尝试创建一个Spring Batch步骤,该步骤读取ProductDetail信息,经处理器生成新的ProductResult并写入MongoDB数据库。使用JdbcPagingItemReader从数据库读取数据时,启动作业抛出以下错误:

java.lang.NullPointerException: Cannot invoke "org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate.getJdbcOperations()" because "this.namedParameterJdbcTemplate" is null.

更换其他Reader可正常运行,仅JdbcPagingItemReader存在问题。已配置查询语句和行映射器,不解为何需要NamedParameterJdbcTemplate,附上配置代码,请问遗漏了什么?

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

问题根源

代码里有两个关键错误导致空指针:

  • 数据源引用错误:itemReader()方法中调用了itemReader.setDataSource(productsDataSource);,但类中注入的数据源变量名是dataSource(带有@Qualifier("productsDataSource")注解),这里的productsDataSource是未定义变量,导致数据源未正确设置,进而使NamedParameterJdbcTemplate无法初始化。
  • 重复设置pageSize:连续调用itemReader.setPageSize(pageSize);和itemReader.setPageSize(chunkSize);,虽不是空指针直接原因,但会覆盖分页大小,建议只保留一个合理设置。

修复后的代码

修改itemReader()方法,修正数据源引用并移除重复的pageSize设置:

public ItemStreamReader<ProductDetail> itemReader() {
    JdbcPagingItemReader<ProductDetail> itemReader = new JdbcPagingItemReader<>();
    // 修正为注入的dataSource变量
    itemReader.setDataSource(dataSource);
    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);
    // 只保留一个pageSize设置,根据需求选择pageSize或chunkSize
    itemReader.setPageSize(pageSize);
    return itemReader;
}

补充说明

JdbcPagingItemReader内部依赖NamedParameterJdbcTemplate执行分页查询,而NamedParameterJdbcTemplate需要通过设置的DataSource初始化。当错误传入未定义的数据源变量时,Reader内部数据源为null,导致NamedParameterJdbcTemplate无法实例化,最终抛出空指针异常。

内容的提问来源于stack exchange,提问作者BreenDeen

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.15 15:56:04