【发布时间】:2021-09-28 16:27:19
【问题描述】:
我有相当大的 CSV 文件,我需要对其进行解析,然后将其保存到 PostgreSQL 中。例如,一个文件包含 2_070_000 条记录,我能够在大约 8 分钟内解析并保留这些记录(单线程)。是否可以使用多个线程来持久化它们?
public void importCsv(MultipartFile csvFile, Class<T> targetClass) {
final var headerMapping = getHeaderMapping(targetClass);
File tempFile = null;
try {
final var randomUuid = UUID.randomUUID().toString();
tempFile = File.createTempFile("data-" + randomUuid, "csv");
csvFile.transferTo(tempFile);
final var csvFileName = csvFile.getOriginalFilename();
final var csvReader = new BufferedReader(new FileReader(tempFile, StandardCharsets.UTF_8));
Stopwatch stopWatch = Stopwatch.createStarted();
log.info("Starting to import {}", csvFileName);
final var csvRecords = CSVFormat.DEFAULT
.withDelimiter(';')
.withHeader(headerMapping.keySet().toArray(String[]::new))
.withSkipHeaderRecord(true)
.parse(csvReader);
final var models = StreamSupport.stream(csvRecords.spliterator(), true)
.map(record -> parseRecord(record, headerMapping, targetClass))
.collect(Collectors.toUnmodifiableList());
// How to save such a large list?
log.info("Finished import of {} in {}", csvFileName, stopWatch);
} catch (IOException ex) {
ex.printStackTrace();
} finally {
tempFile.delete();
}
}
models 包含很多记录。解析成记录是使用并行流完成的,所以速度非常快。我不敢调用 SimpleJpaRepository.saveAll,因为我不确定它在后台会做什么。
问题是:持久化如此庞大的实体列表最有效的方法是什么?
P.S.:非常感谢任何其他改进。
【问题讨论】:
-
目标数据库的架构设计有不同的列对应于 csv 列?
-
使用CopyManager API,它是
copy ... from stdin的Java包装器 -
看起来像是操作动作。如果你正在开发一个运营服务,这没问题,否则你最好不要为这个管理任务编写代码。
-
放弃流,使用经典的 for 循环。保存每个单独的项目和每 x 个项目(比如 100 个)对实体管理器进行刷新和清除。
标签: java postgresql spring-boot hibernate spring-data-jpa