如何在 Spring Boot 中以内存高效的方式迭代 MySQL 中的大量记录

Dee*_*nde 6 java mysql jpa spring-boot

我想从一个表中获取所有记录,findAll并对它们中的每一个进行一些处理,但我不确定如果记录的数量像数百万一样巨大,它是否会出现内存问题。

我已经研究过,Pageable但我不确定如何使用Pageable方法迭代所有数据。甚至可以一次获取几条记录处理它们并再次获取它们直到处理完所有记录?

什么会更好?使用findAll()方法还是 Pageable 方法获取 Iterable 中的所有记录?

Mar*_*vic 22

如果有很多实体,请不要使用 findAll。

如果你想使用分页,你可以这样做:

    Pageable pageRequest = PageRequest.of(0, 200);
    Page<Qmail> onePage = repository.findAll(pageRequest);

    while (!onePage.isEmpty()) {
        pageRequest = pageRequest.next();

        //DO SOMETHING WITH ENTITIES
        onePage.forEach(entity -> System.out.println(entity.getId()));

        onePage = repository.findAll(pageRequest);
    }
Run Code Online (Sandbox Code Playgroud)

  • 否,因为有一个“pageRequest.next()”将移至下一页 (10认同)

Sve*_*ing 5

从 Spring Data 1.8 开始,您可以Stream查看结果。

Stream<Record> findAll();
Run Code Online (Sandbox Code Playgroud)

重要的是,您在此处添加QueryHint有关数据库获取大小的信息。如果设置,它会在内部使用页面来流式传输结果。

将其用于 MySQL 数据库:

@QueryHints(value = @QueryHint(name = org.hibernate.jpa.QueryHints.HINT_FETCH_SIZE, value = "-2147483648"))
Stream<Record> findAll();
Run Code Online (Sandbox Code Playgroud)

对于非 MySQL 数据库,您可以调整获取大小:

@QueryHints(value = @QueryHint(name = org.hibernate.jpa.QueryHints.HINT_FETCH_SIZE, value = "5000"))
Stream<Record> findAll();
Run Code Online (Sandbox Code Playgroud)

并且,如果您不更新/删除记录,请不要忘记将交易设置为只读:

@Transactional(readOnly = true)
Run Code Online (Sandbox Code Playgroud)