Spring Data JPA에서 Query를 사용하는 방법은 여러가지가 있습니다.
1. Query Method
2. @Query 어노테이션
3. Query by Example
이제 각각 쿼리 사용 방법의 예제 코드를 보면서 어떻게 사용하는지 알아보겠습니다.
1. Query Method
일반적으로 JPA에서는 쿼리 메소드를 사용하여 쿼리를 만들 수 있습니다. 우리는 앞서 DB에 쿼리 요청을 하기 위해서 Repository 인터페이스를 만들었습니다. Repository에 메소드를 작성함으로써 정의된 메소드에 따라 쿼리를 자동으로 만들어서 요청 할 수 있게 됩니다.
public interface MemberRepository extends JpaRepository<Member, Integer> {
// MEMBER 테이블의 name column에 검색하는 쿼리
List<Member> findByName(String name);
// MEMBER 테이블의 eamil_address column과 name column에 and 조건으로 검색 하는 쿼리
List<Member> findByEmailAddressAndName(String emailAddress, String name);
}
findByName을 호출하게 되면, JPA에서 다음과 같이 쿼리를 만들어서 요청하게 됩니다.
select m from member m where m.name = ?1
두개 이상의 column에 and 조건으로 조회하고 싶을 때는 column명 사이에 and를 사용하여 메소드를 작성하면 됩니다.
findByEmailAddressAndName을 호출하게 되면 아래와 같이 쿼리를 요청합니다.
select m from member m where m.email_address = ?1 and m.name = ?2
이렇게 정해진 표현식에 맞게 메소드를 작성하면 JPA에서 쿼리를 자동으로 만들어서 요청을 할 수 있습니다. 다음 표에서 JPA에 지원되는 표현식과 해당 표현식이 무엇으로 변화하는지 알아보겠습니다.
예약어 | 샘플 | 쿼리 |
Distinct | fnidDistinctByLastnameAndFirstname | select distinct ... where x.lastname = ?1 x.firstname = ?2 |
And | findByLastnameAndFirstname | ... where x.lastname = ?1 and x.firstname = ?2 |
Or | fintByLastnameOrFirstName | ... where x.lastname = ?1 or x.firstname = ?2 |
Between | firstByStartDateBetween | ... 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 |
IsNull | findByAgeIsNull | ... where x.age is null |
IsNotNull | findByAgeIsNotNull | ... where x.age not null |
Like | findByFirstnameLike | ... where x.firstname like ?1 |
NotLike | findByFirstnameNotLike | ... where x.firstname not like ?1 |
OrderBy | findByAgeOrderByLastnameDesc | ... where x.age = ?1 order by x.lastname desc |
Not | fintByLastnameNot | ... where x.lastname <> ?1 |
In | findByAgeIn(Collection<> ages) | ... where x.age in ?1 |
NotIn | findByAgeNotIn(Collection<> ages) | ... where x.age not in ?1 |
2. @Query 어노테이션
조금 복잡한 쿼리를 사용해야할 경우 정해진 표현식을 사용하는 Query Method는 적합하지 않을 수 있습니다. 이럴 때는 @Query 어노테이션이 좋은 대안이 될 수 있습니다.
@Query 어노테이션은 실행할 메소드 위에 정적 쿼리를 작성하면 됩니다. 이 때 작성하는 쿼리는 JPQL이라는 쿼리로 작성을 해야합니다. Java Persistence Query Language 인 JPQL은 JPA의 특성인 엔티티 객체를 중심으로 작성하는 쿼리 입니다. 그래서 특정 db sql에 의존하지 않는 장점이 있습니다. JPQL 문법의 전체 구조는 SQL과 유사합니다.
public interface MemberRepository extends JpaRepository<Member, Integer> {
@Query("select m from member m where m.name = ?1 and m.age = ?2")
User findMethodA(String name, int age);
@Query("select m from member m where m.name = :name and m.age = :age")
User findMethodB(@Param("name") String param1, @Param("age") int param2)
}
@Query 의 파라미터 바인딩에는 두가지가 있습니다. 첫번째는 위치기반 방법, 두번째는 이름기반 방법입니다.
위치기반 바인딩은 쿼리의 ? 뒤에 숫자와 메소드 파라미터 위치 순서와 일치하면 바인딩을 합니다. 예제코드에서 findMethodA() 코드의 첫번째 파라미터인 String name이 ?1에 바인딩, 두번째 파라미터인 int age가 ?2에 바인딩이 되는 것입니다.
이름기반 바인딩은 @Param("")어노테이션안에 작성된 이름과 쿼리의 : 뒤에 오는 이름과 바인딩이 됩니다. 예제에서는 findMethodB()의 @Param("name")으로 지정된 파마리터 String param1이 :name과 바인딩이 됩니다.
3. Query by Example
QBE(Query by Exmaple)은 JPA에서 생성한 엔티티를 활용하여 쿼리를 요청하는 방식입니다. 먼저 사용할 엔티티 예제 코드와 QBE 샘플 코드입니다.
@Entity
public class Member {
@Id
Integer id;
String name;
Integer age;
// getter, setter..
}
public class MemberService {
@Autowired MemberRepository memberRepository;
public List<User> findMember() {
Member member = new Member();
member.setName("Son");
member.setAge(28);
Example<Member> example = Example.of(member);
return memberRepository.findAll(example);
}
}
Member 엔티티에 name과 age에 값을 할당하고, Example.of()를 통해 find 메소드를 날리면, 아래와 같이 쿼리를 요청하게 됩니다.
select m from member m where m.name = ?1 and m.age= ?2
여기까지 간략하게 Spring Data JPA에서 Query를 다루는 방법을 알아보았는데, 기초 내용만 담았습니다. 더 자세한 내용은 Spring Data JPA - Reference Documentation을 읽어보는게 좋을 것 같습니다.
'Programming > JPA' 카테고리의 다른 글
[Spring Data JPA] 유연한 조회 API만들기(Specification) (0) | 2022.08.17 |
---|---|
[Spring Data JPA] FetchType - 즉시 로딩(EAGER)과 지연 로딩(LAZY) (0) | 2022.08.04 |
[Spring Data JPA] 양방향 순환참조 문제 및 해결방법 (0) | 2022.08.03 |
[Spring Data JPA] JPA 연관관계 매핑(JOIN) (0) | 2022.08.02 |
[Spring Data JPA] JPA 주요 어노테이션(Annotation) (0) | 2022.07.31 |