메소드 네임 쿼리
JPA는 기본적으로 JpaRepository<엔티티 타입, 식별자(PK)타입>을 상속 받음으로써 기본적인 CRUD를 할 수 있는 쿼리를 제공한다. 또한 이것과 별게로 추가적으로 규칙에 의한 메소드 네임만으로 다양한 쿼리문을 실행시킬 수 있는 기능도 제공해준다. 즉, JPA는 메소드의 이름을 분석하여 JPQL을 생성하고 실행한다. 예를 들면 다음과 같다.
1
2
3
|
public interface MemberRepository extends JpaRepository<Member,Long> {
List<Member> findByEmailAndName(String email,String name);
}
|
MemberRepository에 findByEmailAndName이란 메소드를 만들어주었고, 이것을 JPA는 내부적으로 "select m from Member mwhere m.email=:email and m.name=:name" 이란 JPQL로 처리해주어 실행해준다. 이러한 조회 쿼리는 기본적으로 다음과 같은 형태를 취한다.
find[임의로생성가능]By[조건문들] 와 같은 규칙을 가지게 된다. 조건문들에 해당하는 규칙은 다음과 같은 것들이 있다.
Keyword | Sample | JPQL |
And | findByLastnameAndFirstname | where x.lastname = :lastname and x.firstname = :fisrstname |
Or | findByLastnameOrFirstname | where x.lastname = :lastname or x.firstname = :fisrstname |
Is, Equals Not |
findByFistname findByFirstnameNot |
where x.lastname = :firstname where x.lastname != :firstname |
Between | findByStartDateBetween | where x.starteDate between ? and ? |
LessThan LessThanEqual |
findByAgeLessThan findByAgeLessThanEqual |
where x.age < :age where x.age <= :age |
GreaterThan GreaterThanEqual |
findByAgeGreaterThan findByAgeGreaterThanEqual |
where x.age > :age where x.age >= : age |
IsNull IsNotNull |
findByAge(Is)Null findByAge(Is)NotNull |
where x.age is null, where x.age is not null |
In NotIn |
findByAgeIn(Collection<Age> ages>) findByAgeNotIn(Collection<Age> ages>) |
where x.age in ? where x.age not in ? |
IgnoreCase | findByFirstnameIgnoreCase | where UPPER(x.firstname) = UPPER(:firstname) |
부가적으로 다음과 같은 기능도 제공한다.
- distinct : find[Distinct]By
- limit : find[First숫자/Top숫자]By
- orderBy : findBy[OrderBy컬럼Desc/Asc]
- count : countBy
- 클래스변수로 조인 조회 예시 : findByTeam_TeamName(String teamName)
리턴형은 단일인 경우 Optional<엔티티> , 단일이 아닌 경우 List<엔티티> 로 받는것이 가능하다. 위와 같은 메소드 네임 쿼리는 상당히 간편하고 생산성을 높여줄 수 있지만, 쿼리가 복잡해지거나 좀 더 자유로운 쿼리, 직접 SQL을 사용하고 싶을 땐 @Query를 이용할 수 있다.
@Query
@Query 어노테이션을 사용하여 직접 JPA SQL을 입력해줄 수 있다. 다음과 같은 예시를 볼 수 있다.
1
2
3
4
5
|
public interface MemberRepository extends JpaRepository<Member,Long> {
@Query("select m from Member m where m.username=:username and m.age =:age")
List<Member> findUser(@Param("username") String username, @Param("age")int age);
}
|
메소드 네임 쿼리에 비해 SQL을 직접 입력해야하는 과정을 가지지만 좀 더 직관적으로 메소드의 기능에 대해 알 수 가 있다. 또한, Query에서 사용한 parameter들은 @Param으로 입력을 꼭 받아서 사용해주어야 한다.
@Query를 사용한다면 리턴타입에 있어 좀더 자유롭게 사용할 수 가 있게 된다. 리턴타입으로 단일행도 사용할 수 있게 되고, 또한 특정 클래스를 사용할수도 있게 된다. 일반적으로 엔티티 자체를 직접적으로 클라이언트 단으로 보내주는 경우는 운영상 상당히 보안에 취약해질 수 있으므로 보통 Dto 클래스를 사용하여 클라이언트쪽으로 전송을 하게 된다. @Query를 이용하여 Dto클래스를 다음과 같이 사용할 수 있다.
1
2
3
4
5
|
public interface MemberRepository extends JpaRepository<Member,Long>{
@Query("select new study.datajpa.dto.MemberDto(m.id,m.username,t.name) from Member m join m.team t")
List<MemberDto> findMemberDto();
}
|
위와는 다르게 여기선 Member엔티티를 직접 리턴해주는 것이 아니라 id, username, name을 변수로 가지는 MeberDto를 리턴형으로 가지게 되었다. 그것을 위해 @Query에서 쿼리 부분에 new study.datajpa.dto.MemberDto 처럼 직접적으로 경로명을 이용하여 new 연산을 해주었다. 또한, 이 쿼리 문에서 눈여겨 볼것이 있는데 join 방식을 Meber m join m.team 이런식으로 해주었다는 것이다. 이것이 JPA Query의 join 특징이다.
다음편에선 페이징과 정렬, 또한 다른 프레임워크와의 연동을 다루어 보겠다.
출처 : 자바 ORM 표준 JPA 프로그래밍 - 에이콘 출판, 김영한 저
스프링 공식 Document - 링크
'Java&Web' 카테고리의 다른 글
[Apache] Apache와 Tomcat 연동하기 (0) | 2020.12.17 |
---|---|
[WEB] Web Server와 WAS (0) | 2020.12.17 |
[JPA] Spring Data JPA (4) - 사용자 정의 Repository (0) | 2020.08.28 |
[JPA] Spring Data JPA (3) - 페이징과 정렬 (2) | 2020.08.28 |
[JPA] Spring Data JPA (1) - 소개, 기본 (0) | 2020.08.28 |