[Spring] JPA Query Method

JPA의 Query Method에 대해 알아보자.


JpaRepository 상속

  • JpaRepository를 상속한 Repository 인터페이스는 여러 기능이 내장된 상태가 된다.
    • 예시 : public interface UserRepository extends JpaRepository<User, Long> {}
  • 이 경우, findById() 같은 기능은 이미 내장되어 편리하게 사용할 수 있다.
  • 내장 함수

    • JpaReposiroty가 상속하고 있는 인터페이스 중, CrudRepository가 아래와 같이 기본 CRUD 메서드를 가지고 있어 직접 구현하지 않아도 사용할 수 있음.
    •   public interface CrudRepository<T, ID> extends Repository<T, ID> {
          <S extends T> S save(S entity);
      
          <S extends T> Iterable<S> saveAll(Iterable<S> entities);
      
          Optional<T> findById(ID id);
      
          boolean existsById(ID id);
      
          Iterable<T> findAll();
      
          Iterable<T> findAllById(Iterable<ID> ids);
      
          long count();
      
          void deleteById(ID id);
      
          void delete(T entity);
      
          void deleteAllById(Iterable<? extends ID> ids);
      
          void deleteAll(Iterable<? extends T> entities);
      
          void deleteAll();
         }
      

🤔 그렇다면 커스텀 쿼리는 어떻게 할까?

  • Spring Data JPA는 메서드 이름만으로 쿼리를 만들어줌
    • List<User> findByAgeGreaterThan(int n); -> age > n인 유저들

예시:

public interface UserRepository extends JpaRepository<User, Long> {
    List<User> findByName(String name);
}

이 메서드를 호출하면 JPA는 이런 SQL을 자동으로 만든다:

SELECT * FROM user WHERE name = ?;

1. 다양한 조건 연산자

  • 사용 가능한 키워드들:
키워드의미예시SQL
AndAND 조건findByNameAndAgeWHERE name=? AND age=?
OrOR 조건findByNameOrEmailWHERE name=? OR email=?
Between사이 값findByAgeBetween(int a, int b)WHERE age BETWEEN ? AND ?
LessThan / GreaterThan부등호findByAgeGreaterThan(20)WHERE age > 20
IsNull / IsNotNull널 여부findByEmailIsNull()WHERE email IS NULL
In여러 값findByNameIn(List<String> names)WHERE name IN (?, ?, ...)
Like부분일치findByNameLike("%woo%")WHERE name LIKE ?
StartingWith / EndingWith / Containing문자열 검색findByNameStartingWith("s")WHERE name LIKE 's%'

2. 정렬과 페이징도 가능!

List<User> findByAgeGreaterThanOrderByNameAsc(int age);
  • SQL: SELECT * FROM user WHERE age > ? ORDER BY name ASC
Page<User> findByNameContaining(String name, Pageable pageable);
  • 페이징 처리까지 자동으로 해줌!

3. 존재 여부만 알고 싶다면?

boolean existsByEmail(String email);
  • SQL: SELECT COUNT(*) FROM user WHERE email = ?
  • 결과: 해당 이메일이 존재하면 true, 없으면 false

4. 리턴 타입도 다양하게 지원한다.

리턴 타입설명
User단일 객체 (없으면 null)
Optional<User>단일 객체 (안전하게 Optional로 감쌈)
List<User>여러 개
Page<User>페이징 결과
boolean존재 여부 확인

5. 규칙을 안 지키면 어떻게 될까?

findByWhatIsThis() // ← 엔티티에 없는 필드명이면 컴파일은 되지만 실행 시 에러
  • No property whatIsThis found for type User! 같은 예외 발생

🧠 개발자 관점 팁

  • 메서드 이름이 너무 길어지면 @Query를 써서 직접 JPQL 작성하는 게 낫다.
  • 자동 생성 쿼리 → 빠르게 CRUD 만들 때 유용
  • 복잡한 조건@Query 또는 QueryDSL, Specification 권장