在 Spring Boot 应用程序中从数据库获取大数据的最快方法是哪种

问题描述 投票:0回答:1

我目前正在从事 Spring Boot 项目。在我的项目中,我使用标准生成器从 postgres 数据库中获取数据,它对于较小的数据工作正常。但不适用于更大的数据。所以我决定转向其他选项 (JPQL,jdbc 模板)。您能否提供建议在 Spring Boot 中获取数据最快的方法

(**JPQL、jdbc 模板、原始查询**)。您能否提供建议在 Spring Boot 中获取数据最快的方法

spring-boot spring-data-jpa jpql jdbctemplate criteriabuilder
1个回答
0
投票

以下是在 Spring Boot 中处理大型数据集的最佳方法,按性能排序:

  1. JdbcTemplate(最快)

    • 提供最佳性能,因为它最接近数据库
    • 允许直接控制获取大小和连接参数
    • 最适合非常大的数据集(数百万条记录)
    • 无实体映射开销
    • 缺点:需要手动映射
  2. 使用流式处理的本机查询

    • 几乎与 JdbcTemplate 一样快
    • 允许针对您的数据库进行 SQL 优化
    • 支持基于游标的抓取
    • 性能和便利性之间的良好平衡
  3. JPQL 与流媒体

    • 大型数据集的良好性能
    • 比原始 SQL 更易于维护
    • 与数据库无关
    • 支持延迟加载
    • 由于映射开销,比本机查询稍慢
  4. 分页

    • 适合向用户呈现数据
    • 一致的内存使用
    • 与 REST API 配合良好
    • 处理整个数据集可能会更慢,因为它需要多个查询

优化大数据获取的关键建议:

  1. 设置适当的获取大小(通常为 100-1000)
  2. 尽可能使用只读事务
  3. 流式传输结果而不是将所有内容加载到内存中
  4. 考虑面向用户的操作分页
  5. 在数据库上使用正确的索引
  6. 仅选择所需的列,而不是获取整个实体

一些代码示例 // 1. 将 JdbcTemplate 与 Stream 结合使用

@Service
public class UserService {
    @Autowired
    private JdbcTemplate jdbcTemplate;
    
    public void processLargeData() {
        String sql = "SELECT * FROM users WHERE active = true";
        
        jdbcTemplate.setFetchSize(1000); // Set appropriate fetch size
        jdbcTemplate.query(
            sql,
            resultSet -> {
                while (resultSet.next()) {
                    // Process each row here
                    User user = User.builder()
                        .id(resultSet.getLong("id"))
                        .name(resultSet.getString("name"))
                        .build();
                    processUser(user);
                }
            }
        );
    }
}

// 2. 将 JPA/JPQL 与流结合使用

@Service
public class UserJpaService {
    @Autowired
    private EntityManager entityManager;
    
    @Transactional(readOnly = true)
    public void streamUsers() {
        String jpql = "SELECT u FROM User u WHERE u.active = true";
        
        try (Stream<User> userStream = entityManager.createQuery(jpql, User.class)
                .setHint(QueryHints.FETCH_SIZE, 1000)
                .getResultStream()) {
            
            userStream.forEach(this::processUser);
        }
    }
}

// 3. 使用带有游标的本机查询

@Repository
public interface UserRepository extends JpaRepository<User, Long> {
    @Query(value = "SELECT * FROM users WHERE active = true", 
           nativeQuery = true)
    @QueryHints(value = {
        @QueryHint(name = JDBC_FETCH_SIZE, value = "1000"),
        @QueryHint(name = READ_ONLY, value = "true")
    })
    Stream<User> streamAllUsersWithCursor();
}

// 4.使用分页

@Service
public class UserPaginationService {
    @Autowired
    private UserRepository userRepository;
    
    public void processUsersInBatches() {
        int pageSize = 1000;
        int pageNumber = 0;
        Page<User> userPage;
        
        do {
            userPage = userRepository.findAll(PageRequest.of(pageNumber, pageSize));
            processUserBatch(userPage.getContent());
            pageNumber++;
        } while (userPage.hasNext());
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.