乐途乐途
主页
  • 计算机基础

    • TCP/IP
    • Linux
    • HTTP
  • 数据库

    • SQL
    • MySQL 5.7
  • 编程语言

    • C
    • C++
    • Java SE
    • Python2
    • Python3
  • 数据格式

    • JSON
    • XML
  • 认证与安全

    • JWT
  • 工具

    • Markdown
  • Git

    • GitFlow
  • Quartz

    • Quartz
  • Java

    • Maven 入门
    • Maven 进阶
    • MyBatis
    • Spring
    • Spring MVC
  • Java

    • Spring Boot
    • Spring Cloud
    • Spring Cloud Alibaba
    • Spring Security
    • Spring AI
    • Spring Batch
    • Kafka
    • Java 设计模式
  • 缓存

    • Redis
  • 搜索引擎

    • Elasticsearch
  • 分布式协调

    • ZooKeeper
联系
阿里云
主页
  • 计算机基础

    • TCP/IP
    • Linux
    • HTTP
  • 数据库

    • SQL
    • MySQL 5.7
  • 编程语言

    • C
    • C++
    • Java SE
    • Python2
    • Python3
  • 数据格式

    • JSON
    • XML
  • 认证与安全

    • JWT
  • 工具

    • Markdown
  • Git

    • GitFlow
  • Quartz

    • Quartz
  • Java

    • Maven 入门
    • Maven 进阶
    • MyBatis
    • Spring
    • Spring MVC
  • Java

    • Spring Boot
    • Spring Cloud
    • Spring Cloud Alibaba
    • Spring Security
    • Spring AI
    • Spring Batch
    • Kafka
    • Java 设计模式
  • 缓存

    • Redis
  • 搜索引擎

    • Elasticsearch
  • 分布式协调

    • ZooKeeper
联系
阿里云
  • 学习路径
  • 第1章 批处理概述与 Spring Batch 核心理念

    • Spring Batch 概述
    • Job-Instance-Execution 三层生命周期
    • 三层架构
    • Chunk 处理模型
    • Tasklet 处理模型
  • 第2章 Job与作业配置

    • Job 详解
    • Job 配置
    • JobLauncher 详解
    • JobParameters 详解
    • JobRepository 详解
  • 第3章 Step与执行模型

    • Step 详解
    • Step 配置
    • ExecutionContext 详解
    • ItemStream 与状态管理
    • StepScope 与 JobScope
  • 第4章 ItemReader数据读取

    • ItemReader 详解
    • FlatFileItemReader 详解
    • JdbcItemReader 详解
    • MultiResourceItemReader 详解
  • 第5章 ItemProcessor 数据处理

    • ItemProcessor 详解
  • 第6章 ItemWriter 数据写出

    • ItemWriter 详解
    • FlatFileItemWriter 详解
    • CompositeItemWriter 详解
    • JdbcBatchItemWriter 详解
  • 第7章 Chunk 处理与事务边界

    • Chunk 处理模型详解
    • 事务边界
  • 第8章 作业参数与启动

    • 命令行与 Web 启动
  • 第9章 监听器与拦截器

    • 监听器详解
  • 第10章 重启重试与跳过策略

    • 重启与重试
    • 跳过策略
  • 第11章 作业流与条件决策

    • 作业流与条件决策
  • 第12章 分区与并行处理

    • 分区详解
    • 并行 Step 与 Split
  • 第13章 与 Spring Boot 集成实践

    • Spring Boot 集成
  • 第15章 运维与监控

    • 大作业设计模式
    • 运维与监控

ItemReader 详解

本章定位:深入理解 ItemReader——Spring Batch 数据入口的核心抽象,掌握 FlatFileItemReader、JdbcCursorItemReader、JdbcPagingItemReader 等内置实现的使用和选型。

定义与作用

ItemReader<T> 是 Spring Batch 中的核心读接口,定义了逐条读取数据的抽象。它只有一个方法:

@FunctionalInterface
public interface ItemReader&lt;T&gt; {
    @Nullable
    T read() throws Exception;
}

飞翔科技后端开发小崔的理解:

"ItemReader 就像一个快递拆包员——每次调用 read() 就拆出一件包裹。返回 null 表示包裹拆完了。Spring Batch 提供了 FlatFileItemReader(拆文件)、JdbcCursorItemReader(从数据库流式取)和 JdbcPagingItemReader(分页取)等现成的拆包员。"

核心原理

内置 Reader 选型决策

游标 vs 分页

维度JdbcCursorItemReaderJdbcPagingItemReader
读取方式打开游标,逐行流式读取每页 SELECT + LIMIT/OFFSET
数据库连接全程占用一个连接每页获取/释放连接
内存占用低(逐行)低(每页加载)
适用场景中小数据量、简单查询大数据量、长时间运行
线程安全否(游标状态)分页参数可隔离
状态保存行号页码 + 页内偏移

完整示例

场景一:飞翔科技——CSV 文件读取学生成绩

背景:运营部高英提供的学生成绩 CSV 文件 grades.csv:

student_id,course_name,score
STU001,数据结构,85
STU002,操作系统,92
STU003,计算机网络,78
@Bean
@StepScope
public FlatFileItemReader&lt;GradeDTO&gt; gradeCsvReader(
        @Value("#{jobParameters['input.file']}") String inputFile) {
    return new FlatFileItemReaderBuilder&lt;GradeDTO&gt;()
            .name("gradeCsvReader")
            .resource(new FileSystemResource(inputFile))
            .delimited()
            .delimiter(",")
            .names("studentId", "courseName", "score")
            .targetType(GradeDTO.class)
            .linesToSkip(1)       // 跳过 CSV 标题行
            .strict(true)         // 文件不存在时抛异常
            .build();
}

场景二:数据库分页读取

@Bean
public JdbcPagingItemReader&lt;Order&gt; orderDbReader(DataSource dataSource) {
    return new JdbcPagingItemReaderBuilder&lt;Order&gt;()
            .name("orderDbReader")
            .dataSource(dataSource)
            .selectClause("SELECT order_id, customer_name, amount, order_date")
            .fromClause("FROM orders")
            .whereClause("WHERE status = 'PENDING' AND order_date = ?")
            .parameterValues(Map.of("orderDate", "2026-06-13"))
            .sortKeys(Map.of("order_id", Order.ASCENDING)) // 分页必须排序!
            .rowMapper(new BeanPropertyRowMapper<>(Order.class))
            .pageSize(100)
            .saveState(true)
            .build();
}

操作前后对比:

操作前(手动 JDBC):
  Statement stmt = conn.createStatement();
  ResultSet rs = stmt.executeQuery("SELECT * FROM orders WHERE status='PENDING'");
  while (rs.next()) { ... }  // 手动循环、无分页、无断点续传

操作后(JdbcPagingItemReader):
  框架自动分页、每页 100 条、saveState 自动记录分页位置
  崩溃后从上次的页偏移自动恢复

易错场景与避坑

反例一:分页 Reader 忘记设置 sortKeys

// ❌ 没有 sortKeys → 分页结果顺序不确定!
return new JdbcPagingItemReaderBuilder&lt;Order&gt;()
        .name("reader")
        .dataSource(dataSource)
        .selectClause("SELECT * FROM orders")
        .fromClause("FROM orders")
        .pageSize(100)
        // 缺少 .sortKeys() → 分页时数据可能重复或遗漏!
        .build();

反例二:cursor reader 在 partition 中使用

// ❌ JdbcCursorItemReader 非线程安全 → 不能用于分区 Step
@Bean
@StepScope
public JdbcCursorItemReader&lt;Order&gt; reader(DataSource ds) {
    // ... 分区时多个线程共享游标 → 数据错乱
}

正确做法:分区场景使用 PagingItemReader 或设置 saveState=false 并自行处理并发。

面试高频考点

Q1:JdbcCursorItemReader 和 JdbcPagingItemReader 的区别?

Cursor:保持游标打开,逐行流式读取,占用一个连接全程不释放,非线程安全。Paging:分页查询,每页释放连接,通过 sortKeys 保证分页一致性,线程安全。大数据量和分区场景优先 Paging。

Q2:ItemReader.read() 返回 null 代表什么?

返回 null 表示数据已全部读完,Step 结束当前 Chunk 并进入完成流程。这是 Reader 和 Processor 返回 null 的本质区别——Reader 的 null 终止 Step,Processor 的 null 仅过滤当前条。


上一章:ExecutionContext 详解下一章:FlatFileItemReader 详解

下一页
FlatFileItemReader 详解