2024. 10. 19. 19:54ㆍSpring Boot/Spring Data JPA
Spring Data JPA의 Query Creation 기능은 개발자가 리포지토리에서 엔티티에 대한 쿼리를 생성할 수 있도록 지원하는 강력한 도구입니다. 이 기능은 메서드 이름을 기반으로 쿼리를 동적으로 생성하는 방식으로, 복잡한 쿼리를 작성하는 데 필요한 코드를 줄여줍니다. 이제 이 과정과 원리를 아주 상세하게 살펴보겠습니다.
1. 메서드 이름을 통한 쿼리 생성
PersonRepository라는 리포지토리 인터페이스에서 메서드 이름을 통해 여러 쿼리를 생성하는 예를 보겠습니다:
interface PersonRepository extends Repository<Person, Long> {
// 이메일 주소와 성을 기준으로 Person 엔티티 검색
List<Person> findByEmailAddressAndLastname(EmailAddress emailAddress, String lastname);
// 성 또는 이름을 기준으로 중복을 제거한 Person 리스트 검색
List<Person> findDistinctPeopleByLastnameOrFirstname(String lastname, String firstname);
List<Person> findPeopleDistinctByLastnameOrFirstname(String lastname, String firstname);
// 성을 기준으로 대소문자를 무시하고 Person 리스트 검색
List<Person> findByLastnameIgnoreCase(String lastname);
// 성과 이름을 기준으로 대소문자를 무시하고 Person 리스트 검색
List<Person> findByLastnameAndFirstnameAllIgnoreCase(String lastname, String firstname);
// 성을 기준으로 이름을 오름차순으로 정렬하여 Person 리스트 검색
List<Person> findByLastnameOrderByFirstnameAsc(String lastname);
// 성을 기준으로 이름을 내림차순으로 정렬하여 Person 리스트 검색
List<Person> findByLastnameOrderByFirstnameDesc(String lastname);
}
이 코드에서 각 메서드는 특정 조건을 가지고 데이터베이스에서 Person 엔티티를 검색하는 쿼리를 생성합니다.
2. 메서드 이름의 구조
메서드 이름을 파싱하는 과정은 크게 주제(subject)와 술어(predicate)로 나눌 수 있습니다:
- 주제(Subject):
- 메서드 이름의 처음 부분으로, 쿼리의 주체를 정의합니다. 주제는 보통
findBy
,existsBy
와 같은 키워드로 시작합니다. 이 부분은 리포지토리가 어떤 데이터를 검색할 것인지를 나타냅니다.
- 메서드 이름의 처음 부분으로, 쿼리의 주체를 정의합니다. 주제는 보통
- 술어(Predicate):
By
다음의 부분으로, 실제 검색 조건을 정의합니다. 이 부분은 엔티티의 속성을 기준으로 다양한 조건을 설정할 수 있습니다.
3. 쿼리 메서드 이름 해석
- 쿼리 메서드 이름의 해석은 기본적으로 메서드 이름에서 주제와 술어를 나누는 것으로 시작합니다.
- 예를 들어,
findByLastnameAndFirstname(String lastname, String firstname)
메서드는lastname
과firstname
속성을 사용하여 검색 조건을 설정합니다. findDistinctPeopleByLastnameOrFirstname
메서드에서Distinct
키워드는 중복 제거를 의미하며, 이로 인해 반환되는 결과에서 중복된 엔티티가 제외됩니다.
4. 기본적인 조건 생성
쿼리 메서드에서는 엔티티 속성에 대한 조건을 정의하고, And
또는 Or
키워드를 사용하여 조건을 조합할 수 있습니다. 예를 들어:
findByLastnameAndFirstname(...)
는 성과 이름이 모두 일치하는 조건을 가진 엔티티를 검색합니다.findByLastnameOrFirstname(...)
는 성이나 이름이 일치하는 조건을 가진 엔티티를 검색합니다.
5. 다양한 쿼리 조건
쿼리 메서드는 특정한 조건 외에도 다양한 추가 기능을 지원합니다:
- 대소문자 무시:
findByLastnameIgnoreCase(...)
와 같이 메서드 이름에IgnoreCase
를 추가하면, 대소문자를 구분하지 않고 검색을 수행합니다. 이는 사용자가 입력하는 값의 대소문자에 관계없이 검색할 수 있도록 도와줍니다.findByLastnameAndFirstnameAllIgnoreCase(...)
는 여러 속성에 대해 대소문자를 무시하여 검색합니다.
- 정렬 지원:
findByLastnameOrderByFirstnameAsc(...)
또는findByLastnameOrderByFirstnameDesc(...)
와 같이OrderBy
절을 추가하면 검색 결과를 특정 속성에 따라 오름차순 또는 내림차순으로 정렬할 수 있습니다.
6. 쿼리 메서드의 예
여기서 몇 가지 예를 들어보겠습니다:
- 이메일 주소와 성으로 검색:
- 이 메서드는 주어진 이메일 주소와 성을 가진 Person 엔티티를 반환합니다.
List<Person> findByEmailAddressAndLastname(EmailAddress emailAddress, String lastname);
- 중복 제거된 성과 이름으로 검색:
- 이 메서드는 성 또는 이름이 주어진 값과 일치하는 Person 엔티티를 반환하며, 중복된 결과는 제거됩니다.
List<Person> findDistinctPeopleByLastnameOrFirstname(String lastname, String firstname);
7. 지원되는 연산자
쿼리 메서드에서는 여러 연산자를 사용할 수 있습니다:
- Between: 특정 범위 내의 값을 찾습니다.
- LessThan / GreaterThan: 특정 값보다 작은/큰 값을 찾습니다.
- Like: 패턴 일치를 통해 검색합니다.
이 연산자들은 데이터 저장소에 따라 다를 수 있으므로, 각 저장소의 문서에서 어떤 연산자가 지원되는지 확인해야 합니다.
8. 대소문자 무시 지원
개별 속성에 대해 대소문자를 무시하는 플래그를 설정할 수 있으며, 이는 메서드 이름에 IgnoreCase
를 추가하여 쉽게 사용할 수 있습니다.
예를 들어, findByLastnameIgnoreCase(...)
는 대소문자 구분 없이 성을 검색하며, 사용자에게 보다 유연한 검색 기능을 제공합니다.
Table 1. Supported keywords inside method names
Keyword | Sample | JPQL snippet |
Distinct | findDistinctByLastnameAndFirstname | select distinct … where x.lastname = ?1 and x.firstname = ?2 |
And | findByLastnameAndFirstname | … where x.lastname = ?1 and x.firstname = ?2 |
Or | findByLastnameOrFirstname | … where x.lastname = ?1 or x.firstname = ?2 |
Is, Equals | findByFirstname,findByFirstnameIs,findByFirstnameEquals | … where x.firstname = ?1 |
Between | findByStartDateBetween | … where x.startDate between ?1 and ?2 |
LessThan | findByAgeLessThan | … where x.age < ?1 |
LessThanEqual | findByAgeLessThanEqual | … where x.age <= ?1 |
GreaterThan | findByAgeGreaterThan | … where x.age > ?1 |
GreaterThanEqual | findByAgeGreaterThanEqual | … where x.age >= ?1 |
After | findByStartDateAfter | … where x.startDate > ?1 |
Before | findByStartDateBefore | … where x.startDate < ?1 |
IsNull, Null | findByAge(Is)Null | … where x.age is null |
IsNotNull, NotNull | findByAge(Is)NotNull | … where x.age is not null |
Like | findByFirstnameLike | … where x.firstname like ?1 |
NotLike | findByFirstnameNotLike | … where x.firstname not like ?1 |
StartingWith | findByFirstnameStartingWith | … where x.firstname like ?1 (parameter bound with appended %) |
EndingWith | findByFirstnameEndingWith | … where x.firstname like ?1 (parameter bound with prepended %) |
Containing | findByFirstnameContaining | … where x.firstname like ?1 (parameter bound wrapped in %) |
OrderBy | findByAgeOrderByLastnameDesc | … where x.age = ?1 order by x.lastname desc |
Not | findByLastnameNot | … where x.lastname <> ?1 |
In | findByAgeIn(Collection<Age> ages) | … where x.age in ?1 |
NotIn | findByAgeNotIn(Collection<Age> ages) | … where x.age not in ?1 |
True | findByActiveTrue() | … where x.active = true |
False | findByActiveFalse() | … where x.active = false |
IgnoreCase | findByFirstnameIgnoreCase | … where UPPER(x.firstname) = UPPER(?1) |
Spring Data JPA의 Query Creation 기능은 메서드 이름을 사용하여 자동으로 쿼리를 생성하는 강력한 기능입니다. 이를 통해 개발자는 복잡한 SQL 문을 직접 작성할 필요 없이, 간단한 메서드 이름으로 원하는 데이터를 쉽게 검색할 수 있습니다. 이러한 기능은 개발자의 생산성을 높이고 코드의 가독성을 개선하는 데 기여합니다.
이 기능을 잘 활용하면, 보다 직관적이고 유지보수하기 쉬운 데이터 액세스 코드를 작성할 수 있습니다.
'Spring Boot > Spring Data JPA' 카테고리의 다른 글
Property Expressions (0) | 2024.10.19 |
---|---|
Reserved Method Names (1) | 2024.10.19 |
Query Lookup Strategies (0) | 2024.10.19 |
Defining Query Methods (0) | 2024.10.19 |
Persisting Entities (0) | 2024.10.19 |