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

如何用SpringBatch从单个CSV文件向多表持久化数据?

SpringBatch实现CSV数据写入SQL Server多表方案

完全可以实现,下面是基于Spring Boot + SpringBatch + SQL Server的具体示例代码:

1. 依赖配置(pom.xml)

先引入必要的依赖:

<dependencies>
    <!-- Spring Boot Starter Batch -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-batch</artifactId>
    </dependency>
    <!-- SQL Server JDBC驱动 -->
    <dependency>
        <groupId>com.microsoft.sqlserver</groupId>
        <artifactId>mssql-jdbc</artifactId>
        <scope>runtime</scope>
    </dependency>
    <!-- Spring Data JPA(简化数据库操作) -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-jpa</artifactId>
    </dependency>
</dependencies>

2. 数据库实体类

假设CSV每行数据对应三张关联表:用户表、订单表、订单详情表,示例实体如下:

// 用户表实体
@Entity
@Table(name = "user_info")
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String username;
    private String email;
    
    // getter、setter、无参/全参构造方法
}

// 订单表实体
@Entity
@Table(name = "order_info")
public class Order {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private Long userId; // 关联用户表主键
    private String orderNo;
    private LocalDateTime createTime;
    
    // getter、setter、无参/全参构造方法
}

// 订单详情表实体
@Entity
@Table(name = "order_detail")
public class OrderDetail {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private Long orderId; // 关联订单表主键
    private String productName;
    private Integer quantity;
    
    // getter、setter、无参/全参构造方法
}

3. CSV读取器(ItemReader)

假设CSV格式为username,email,orderNo,productName,quantity,配置读取器解析CSV:

@Bean
public FlatFileItemReader<String[]> csvReader() {
    FlatFileItemReader<String[]> reader = new FlatFileItemReader<>();
    reader.setResource(new ClassPathResource("data.csv")); // 指定CSV文件路径
    reader.setLinesToSkip(1); // 跳过表头行
    
    // 按逗号分割CSV字段
    DelimitedLineTokenizer tokenizer = new DelimitedLineTokenizer();
    tokenizer.setDelimiter(",");
    tokenizer.setNames("username", "email", "orderNo", "productName", "quantity");
    
    DefaultLineMapper<String[]> lineMapper = new DefaultLineMapper<>();
    lineMapper.setLineTokenizer(tokenizer);
    lineMapper.setFieldSetMapper(fieldSet -> new String[]{
        fieldSet.readString("username"),
        fieldSet.readString("email"),
        fieldSet.readString("orderNo"),
        fieldSet.readString("productName"),
        fieldSet.readInt("quantity") + ""
    });
    reader.setLineMapper(lineMapper);
    return reader;
}

4. 数据处理器(ItemProcessor)

将CSV行数据转换为三张表的实体,用自定义DTO统一传递:

// 自定义DTO,封装三张表的实体数据
public class MultiTableData {
    private User user;
    private Order order;
    private OrderDetail orderDetail;
    
    // getter、setter、构造方法
}

@Bean
public ItemProcessor<String[], MultiTableData> dataProcessor() {
    return csvRow -> {
        // 构建用户实体
        User user = new User();
        user.setUsername(csvRow[0]);
        user.setEmail(csvRow[1]);
        
        // 构建订单实体
        Order order = new Order();
        order.setOrderNo(csvRow[2]);
        order.setCreateTime(LocalDateTime.now());
        
        // 构建订单详情实体
        OrderDetail detail = new OrderDetail();
        detail.setProductName(csvRow[3]);
        detail.setQuantity(Integer.parseInt(csvRow[4]));
        
        return new MultiTableData(user, order, detail);
    };
}

5. 多表写入器(ItemWriter)

按外键关联顺序依次写入三张表:

@Bean
public ItemWriter<MultiTableData> multiTableWriter(
        JpaRepository<User, Long> userRepo,
        JpaRepository<Order, Long> orderRepo,
        JpaRepository<OrderDetail, Long> detailRepo) {
    
    return items -> {
        for (MultiTableData data : items) {
            // 先保存用户,获取主键ID
            User savedUser = userRepo.save(data.getUser());
            // 关联用户ID到订单,保存订单
            Order order = data.getOrder();
            order.setUserId(savedUser.getId());
            Order savedOrder = orderRepo.save(order);
            // 关联订单ID到详情,保存订单详情
            OrderDetail detail = data.getOrderDetail();
            detail.setOrderId(savedOrder.getId());
            detailRepo.save(detail);
        }
    };
}

6. Job与Step配置

@Configuration
@EnableBatchProcessing
public class BatchConfig {

    @Autowired
    private JobBuilderFactory jobBuilderFactory;

    @Autowired
    private StepBuilderFactory stepBuilderFactory;

    @Bean
    public Step csvToMultiTableStep(ItemReader<String[]> reader,
                                    ItemProcessor<String[], MultiTableData> processor,
                                    ItemWriter<MultiTableData> writer) {
        return stepBuilderFactory.get("csvToMultiTableStep")
                .<String[], MultiTableData>chunk(100) // 每100条数据批量提交一次
                .reader(reader)
                .processor(processor)
                .writer(writer)
                .build();
    }

    @Bean
    public Job csvToMultiTableJob(Step csvToMultiTableStep) {
        return jobBuilderFactory.get("csvToMultiTableJob")
                .incrementer(new RunIdIncrementer())
                .flow(csvToMultiTableStep)
                .end()
                .build();
    }
}

7. 数据库配置(application.yml)

spring:
  datasource:
    url: jdbc:sqlserver://localhost:1433;databaseName=your_db_name;encrypt=true;trustServerCertificate=true
    username: your_username
    password: your_password
    driver-class-name: com.microsoft.sqlserver.jdbc.SQLServerDriver
  jpa:
    hibernate:
      ddl-auto: update # 生产环境建议改为none
    show-sql: true
  batch:
    job:
      enabled: true # 项目启动时自动执行Job,测试用,生产可按需关闭

核心逻辑:通过FlatFileItemReader读取CSV每行数据,在ItemProcessor中转换为多表实体,最后在ItemWriter里按外键依赖顺序(用户→订单→订单详情)依次写入数据库。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.19 20:40:49