
SOFTMOA TECHNOLOGY
Spring Data JPA 쿼리 메서드 완벽 가이드
소프트모아가 정리한 기술 기록입니다.
Contents
작성일 2025. 11. 30.
Spring Data JPA 쿼리 메서드 완벽 가이드
Spring Data JPA의 쿼리 메서드를 활용하면 SQL 없이 메서드 이름만으로 복잡한 쿼리를 작성할 수 있습니다.
기본 쿼리 메서드
public interface UserRepository extends JpaRepository<User, Long> {
// 기본 조회
Optional<User> findByEmail(String email);
List<User> findByName(String name);
// 복합 조건
List<User> findByNameAndAge(String name, int age);
List<User> findByNameOrEmail(String name, String email);
// 비교 연산
List<User> findByAgeGreaterThan(int age);
List<User> findByAgeLessThanEqual(int age);
List<User> findByAgeBetween(int start, int end);
// NULL 처리
List<User> findByNicknameIsNull();
List<User> findByNicknameIsNotNull();
// LIKE 검색
List<User> findByNameContaining(String keyword);
List<User> findByNameStartingWith(String prefix);
List<User> findByNameEndingWith(String suffix);
// IN 절
List<User> findByAgeIn(Collection<Integer> ages);
// 정렬
List<User> findByNameOrderByAgeDesc(String name);
// 페이징
Page<User> findByAge(int age, Pageable pageable);
// Top/First
List<User> findTop5ByOrderByCreatedAtDesc();
Optional<User> findFirstByNameOrderByAgeDesc(String name);
// 존재 여부
boolean existsByEmail(String email);
// 개수
long countByAge(int age);
// 삭제
void deleteByEmail(String email);
}@Query 어노테이션
// JPQL
@Query("SELECT u FROM User u WHERE u.email LIKE %:domain")
List<User> findByEmailDomain(@Param("domain") String domain);
// Native Query
@Query(value = "SELECT * FROM users WHERE created_at > :date", nativeQuery = true)
List<User> findRecentUsers(@Param("date") LocalDateTime date);
// 업데이트
@Modifying
@Query("UPDATE User u SET u.status = :status WHERE u.id = :id")
int updateStatus(@Param("id") Long id, @Param("status") String status);
// DTO 프로젝션
@Query("SELECT new com.example.UserDto(u.name, u.email) FROM User u")
List<UserDto> findAllUserDto();페이징과 정렬
// 서비스 계층
Pageable pageable = PageRequest.of(0, 10, Sort.by("createdAt").descending());
Page<User> page = userRepository.findByAge(25, pageable);
// 결과 활용
List<User> users = page.getContent();
long total = page.getTotalElements();
int totalPages = page.getTotalPages();
boolean hasNext = page.hasNext();동적 쿼리 (Specification)
public class UserSpecification {
public static Specification<User> hasName(String name) {
return (root, query, cb) ->
name == null ? null : cb.equal(root.get("name"), name);
}
public static Specification<User> ageGreaterThan(Integer age) {
return (root, query, cb) ->
age == null ? null : cb.greaterThan(root.get("age"), age);
}
}
// 사용
List<User> users = userRepository.findAll(
Specification.where(hasName("Kim")).and(ageGreaterThan(20))
);프로젝션 (필요한 필드만)
// 인터페이스 프로젝션
public interface UserSummary {
String getName();
String getEmail();
}
List<UserSummary> findByAge(int age);
// 클래스 프로젝션 (DTO)
public record UserDto(String name, String email) {}
@Query("SELECT new com.example.UserDto(u.name, u.email) FROM User u")
List<UserDto> findAllDto();N+1 문제 해결
// Fetch Join
@Query("SELECT u FROM User u JOIN FETCH u.orders WHERE u.id = :id")
Optional<User> findByIdWithOrders(@Param("id") Long id);
// EntityGraph
@EntityGraph(attributePaths = {"orders", "addresses"})
Optional<User> findById(Long id);Share this
Spring
Showing 1 to 10 of 79 entries
