Entity Mapping
@Entity
@Table(name = "users")
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(nullable = false, length = 100)
private String name;
@Column(unique = true, nullable = false)
private String email;
@OneToMany(mappedBy = "user", fetch = FetchType.LAZY)
private List<Order> orders;
@CreationTimestamp
private LocalDateTime createdAt;
}
Repository
Spring Data JPA tự generate implementation từ method name:
public interface UserRepository extends JpaRepository<User, Long> {
// SELECT * FROM users WHERE email = ?
Optional<User> findByEmail(String email);
// SELECT * FROM users WHERE name LIKE ?
List<User> findByNameContaining(String keyword);
// Custom query
@Query("SELECT u FROM User u JOIN FETCH u.orders WHERE u.id = :id")
Optional<User> findByIdWithOrders(@Param("id") Long id);
}
N+1 Problem
// N+1 queries!
List<User> users = userRepository.findAll(); // 1 query
for (User u : users) {
u.getOrders().size(); // N queries (1 per user)
}
// Fix: JOIN FETCH
@Query("SELECT u FROM User u JOIN FETCH u.orders")
List<User> findAllWithOrders(); // 1 query
Key insight: Default fetch type cho
@OneToManylà LAZY — tốt cho performance. Nhưng phải ý thức N+1 problem và dùng JOIN FETCH khi cần.