【问题标题】:How to persist data to a MySql database from a 32k row Excel using JPA Pagination?如何使用 JPA 分页将数据从 32k 行 Excel 持久化到 MySql 数据库?
【发布时间】:2020-12-02 22:18:39
【问题描述】:

我有一个包含 32k 行的大型 Excel 文件,以及一个将 Excel 数据持久保存到 mySQL 数据库的 Java-Spring 代码。我的代码适用于大约 6k 行,但由于 JPA 限制,不适用于整个 Excel。我读到它可以用 JPA 分页来完成,但到目前为止,我只发现从 DB 收集数据(已经与数据一起保存)并呈现到 UI 的信息。 Excel 文件包含 32k 种药物,这些行将被持久化到数据库中。

我有这个Controller层,方法如下:

    public ResponseEntity<ResponseMessage> uploadFile(@RequestParam("file") MultipartFile file,
                                                    @RequestParam(defaultValue = "0") int page,
                                                    @RequestParam(defaultValue = "6000") int size) {

        String message = "";

        if (ExcelHelper.hasExcelFormat(file)) {
            try {
// the following 6 row are my patetic attempt to resolve with pagination
               List<Medicine> medicines = new ArrayList<>();
                Pageable paging = PageRequest.of(page, size);
                Page<Medicine> pageMedicamente = medicineRepositoryDao.save(paging);

                medicines = pageMedicamente.getContent();
                medicineService.save(file);

                message = "Uploaded the file successfully: " + file.getOriginalFilename();
                return ResponseEntity.status(HttpStatus.OK).body(new ResponseMessage(message));
            } catch (Exception e) {
                message = "Could not upload the file: " + file.getOriginalFilename() + "!";
                return ResponseEntity.status(HttpStatus.EXPECTATION_FAILED).body(new ResponseMessage(message));
            }
        }

还有Repository层:

@Repository
public interface MedicineRepositoryDao extends JpaRepository<Medicine, Long> {


    Page<Medicine> save( Pageable pageable);

}

还有服务层:

        try {
            List<Medicine> medicines = ExcelHelper.excelToMedicine(file.getInputStream());
            medicineRepositoryDao.saveAll(medicines);
        } catch (IOException e) {
            throw new RuntimeException("fail to store excel data: " + e.getMessage());
        }
    }

【问题讨论】:

    标签: java spring-boot jpa spring-data-jpa pagination


    【解决方案1】:

    我认为您在这里混淆了几件事。

    1. 我认为 Spring 对您可以在此处保留的行数没有任何相关限制。但是 JPA 可以。 JPA 确实保留了对您保存在其一级缓存中的任何实体的引用。因此,对于大量的行/实体,这会占用内存并且还会使某些操作变慢,因为实体会被逐个查找或处理。

    2. 分页是用来读取实体的,不是用来保存的。

    在这种情况下你有几个选择。

    1. 不要使用 JPA。对于简单地从文件写入数据并将其写入数据库,JPA 几乎没有任何好处。这几乎可以使用JdbcTemplateNamedParameterJdbcTemplate 轻松执行,并且速度会更快,因为跳过了JPA 的开销,在这种情况下您无论如何都不会从中受益。如果你想使用 ORM,你可能想看看 Spring Data JDBC,它在概念上更简单,不保留对实体的引用,因此在这种情况下应该显示出更好的特性。我建议不要在这里使用 ORM,因为你似乎没有从拥有实体中受益,所以创建它们然后让 ORM 从中提取数据真的是浪费时间。

    2. 将您的导入分批进行。这意味着你坚持例如一次 1000 行,将它们写入数据库并提交事务,然后再继续接下来的 1000 行。对于 JPA 来说,由于上述原因,这几乎是必要的。使用 JDBC(即JdbcTemplate&Co),这对于 32K 行可能不是必需的,但可能会提高性能,并且可能对插入失败时的可恢复性有用。 Spring Batch 将帮助您实现这一点。

    3. 虽然前一点谈到了将导入分解为块的意义上的批处理,但您还应该研究 JDBC 端的批处理,您可以在其中发送多个语句,或者一次发送具有多组参数的单个语句。数据库,这将再次提高性能。

    4. 最后,Javaverse 之外的其他替代方案可能更适合这项工作。一些数据库有工具可以非常高效地加载平面文件。

    【讨论】:

    • 您的信息很受欢迎,谢谢!我使用 Hibernate 作为 ORM。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-02-25
    • 1970-01-01
    • 1970-01-01
    • 2013-07-25
    • 2011-07-13
    • 2015-08-19
    相关资源
    最近更新 更多