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

    • 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章 运维与监控

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

ItemWriter 详解

本章定位:深入理解 ItemWriter——Spring Batch 数据出口的核心抽象,掌握批量写入机制、事务保证和内置实现选型。

定义与作用

ItemWriter<T> 是 Spring Batch 中的核心写接口,负责将 Chunk 中的一组数据批量写出到目标系统(数据库、文件、消息队列)。

@FunctionalInterface
public interface ItemWriter&lt;T&gt; {
    void write(Chunk&lt;? extends T&gt; chunk) throws Exception;
}

关键设计:write() 接收的是 Chunk(一组数据),不是单条——这保证了一次事务提交对应一次数据批量写出。

飞翔科技架构师白歌的比喻:

"Writer 是仓库管理员。Reader 一件一件搬进来,Processor 加工好堆在托盘上,等托盘堆满(Chunk Size 达标),Writer 一次性把一整个托盘入库。入库成功 → 事务提交。"

核心原理

Writer 在 Chunk 循环中的位置

内置 Writer 选型

Writer数据目标关键特性
JdbcBatchItemWriter数据库使用 PreparedStatement.addBatch() 批量执行
FlatFileItemWriter文件逐行写入,支持定长/分隔符格式
CompositeItemWriter多目标同时写入多个 Writer
StaxEventItemWriterXML 文件基于 StAX
JsonFileItemWriterJSON 文件流式 JSON 生成
JpaItemWriterJPA 数据库entityManager.merge() 逐条
KafkaItemWriterKafka批量发送消息

完整示例

场景一:飞翔科技——JdbcBatchItemWriter 批量写入学生数据

@Bean
public JdbcBatchItemWriter&lt;StudentEntity&gt; studentWriter(DataSource dataSource) {
    return new JdbcBatchItemWriterBuilder&lt;StudentEntity&gt;()
            .dataSource(dataSource)
            .sql("INSERT INTO students (student_id, name, email, age, import_time) "
               + "VALUES (:studentId, :name, :email, :age, :importTime)")
            .itemSqlParameterSourceProvider(new BeanPropertyItemSqlParameterSourceProvider<>())
            .assertUpdates(true)       // 断言每次更新的行数
            .build();
}

运行结果(Chunk Size=50):

Chunk 1: 50 items → PreparedStatement.addBatch() × 50 → executeBatch() → 50 rows inserted → COMMIT
Chunk 2: 50 items → ... → 50 rows → COMMIT
...
Chunk 100: 50 items → ... → 50 rows → COMMIT
Step 完成: writeCount=5000

场景二:FlatFileItemWriter 生成导出文件

@Bean
public FlatFileItemWriter&lt;StudentEntity&gt; studentExportWriter() {
    return new FlatFileItemWriterBuilder&lt;StudentEntity&gt;()
            .name("studentExportWriter")
            .resource(new FileSystemResource("export_students.csv"))
            .delimited()
            .delimiter(",")
            .names("studentId", "name", "email", "age")
            .headerCallback(writer -> writer.write("student_id,name,email,age"))
            .footerCallback(writer -> writer.write("# Generated by Spring Batch"))
            .encoding("UTF-8")
            .build();
}

操作前后对比:

操作前(手动 JDBC):
  for (Student s : list) {
      PreparedStatement ps = conn.prepareStatement("INSERT ...");
      ps.setString(1, s.getId());
      // ... 逐个设置、执行
  }
  conn.commit();
  问题:每条一条 SQL,100 万条 = 100 万次网络往返

操作后(JdbcBatchItemWriter):
  Chunk size 500 → 每 500 条 addBatch() → executeBatch() → 1 次网络往返
  100 万条 = 2000 次网络往返(减少 500 倍)

易错场景与避坑

反例一:JdbcBatchItemWriter 使用错误的 Provider

// ❌ 使用 MapItemSqlParameterSourceProvider 但 SQL 用 :propertyName
return new JdbcBatchItemWriterBuilder&lt;StudentEntity&gt;()
        .dataSource(dataSource)
        .sql("INSERT INTO students VALUES (:studentId, :name, :email)")
        .itemSqlParameterSourceProvider(
            new MapItemSqlParameterSourceProvider())  // ❌ 需要 Map 但实体是 POJO
        .build();

正确做法:POJO 实体用 BeanPropertyItemSqlParameterSourceProvider,Map 用 MapItemSqlParameterSourceProvider。

反例二:Writer 的 write() 中逐条提交

// ❌ 在 write() 内部逐条 commit → 破坏事务一致性
public void write(Chunk<? extends Student> chunk) {
    for (Student s : chunk.getItems()) {
        jdbcTemplate.update("INSERT ...", s.getId(), s.getName());
        // ❌ 不要在这里手动提交!
    }
}

面试高频考点

Q1:ItemWriter.write() 为什么接收 Chunk 而不是单条?

为了批量写入优化。JDBC 的 executeBatch()、文件的 BufferedWriter.flush() 都是批量操作。如果逐条写入,性能会极度下降。Chunk 机制保证了一次事务内尽可能多的数据被一次性写入。

Q2:JpaItemWriter 和 JdbcBatchItemWriter 的性能差异?

JpaItemWriter 逐条调用 entityManager.merge(),适合小数据量和需要 JPA 级联操作的场景。JdbcBatchItemWriter 使用 JDBC Batch API 批量写入,性能高 5-10 倍,适合大规模 ETL。


上一章:ItemProcessor 详解下一章:FlatFileItemWriter 详解

下一页
FlatFileItemWriter 详解