Java&Web

[JPA] Spring Data JPA (2) - 메소드 네임 쿼리, @Query

프로그래민 2020. 8. 28. 13:34
반응형

메소드 네임 쿼리

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 - 링크

 

반응형