如何用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
相关产品推荐
相关产品推荐

