在 JPA(Java Persistence API)中确实存在 Lazy Loading(懒加载)与 N+1 查询问题,这两个概念往往是一起讨论的,因为懒加载是 N+1 问题的主要诱因之一。
✅ 什么是 Lazy Loading(懒加载)?
在 JPA 中,当你使用 @OneToMany、@ManyToOne 等关联关系时,可以指定加载策略:
• FetchType.LAZY:懒加载,表示当你首次访问该关联属性时,才会从数据库查询数据。
• FetchType.EAGER:立即加载,表示在主实体加载时,关联实体也立刻加载。
懒加载的好处是节省性能,但也容易带来 N+1 查询问题。
❌ 什么是 N+1 查询问题?
假设你有一个实体 User,每个用户关联一个 Department(部门)。你写了一条查询,加载了 10 个用户:
List<User> users = userRepository.findAll(); // 一次查询
然后你访问每个用户的部门:
for (User user : users) {
System.out.println(user.getDepartment().getName()); // 每次访问都触发一次查询
}
结果是:
• 第一次查询 users:1 次
• 每个 user.getDepartment() 触发懒加载:10 次
👉 总共执行了 1 + 10 = 11 次查询,这就是 N+1 查询问题!
🔧 如何解决 N+1 查询问题?
1. 使用 Fetch Join:
在 JPQL/HQL 中显式使用 join fetch:
@Query("SELECT u FROM User u JOIN FETCH u.department")
List<User> findAllWithDepartment();
2. 使用 EntityGraph:
@EntityGraph(attributePaths = "department")
List<User> findAll();
3. 适当使用 EAGER,但小心内存开销和无限递归问题。
4. Hibernate 的 Batch Fetching:
配置 hibernate.default_batch_fetch_size,让懒加载时批量加载多个对象,减少 SQL 次数。
🧠 总结一句话:
懒加载本身并不是问题,但如果你没有控制好访问时机和批量加载策略,就可能导致 N+1 查询问题,严重影响性能。
浙公网安备 33010602011771号