| Lazy | Eager | |
|---|---|---|
| Load khi | Lần đầu truy cập field | Luôn load cùng entity chính |
| Default | @OneToMany, @ManyToMany | @ManyToOne, @OneToOne |
java
@Entity
class Order {
@OneToMany(fetch = FetchType.LAZY) // default
private List<OrderItem> items;
@ManyToOne(fetch = FetchType.EAGER) // default
private Customer customer;
}Vấn đề Eager: load tất cả dù không cần → waste.
Vấn đề Lazy: LazyInitializationException khi truy cập ngoài transaction.
Fix lazy:
- @Transactional trên method service (giữ session mở).
- JOIN FETCH trong JPQL:
java
@Query("SELECT o FROM Order o JOIN FETCH o.items WHERE o.id = :id")
Optional<Order> findWithItems(@Param("id") Long id);- DTO projection — chỉ lấy field cần.
Best practice: mặc định Lazy, chỉ Eager/JOIN FETCH khi chắc chắn cần trong mọi use case.
| Lazy | Eager | |
|---|---|---|
| Loads when | First field access | Always with the parent entity |
| Default | @OneToMany, @ManyToMany | @ManyToOne, @OneToOne |
java
@Entity
class Order {
@OneToMany(fetch = FetchType.LAZY)
private List<OrderItem> items;
@ManyToOne(fetch = FetchType.EAGER)
private Customer customer;
}Eager problem: loads all associations even when not needed → wasted queries.
Lazy problem: LazyInitializationException when accessed outside a transaction.
Lazy fixes:
- @Transactional on the service method.
- JOIN FETCH in JPQL:
java
@Query("SELECT o FROM Order o JOIN FETCH o.items WHERE o.id = :id")
Optional<Order> findWithItems(@Param("id") Long id);- DTO projection.
Best practice: default to Lazy, use Eager/JOIN FETCH only when data is always needed.