@Query
어노테이션을 사용해서 Repository 인터페이스 쿼리 직접 정의public interface MemberRepository extends JpaRepository<Member, Long> {
// 이름과 나이를 기준으로 회원을 조회
List<Member> findByUsernameAndAgeGreaterThan(String username, int age);
}
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 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) |
findMemberBy
: ...에 식별하기 위한 내용(설명)이 들어가도 된다.(생략 가능)long
boolean
long
참고: 이 기능은 엔티티의 필드명이 변경되면 인터페이스에 정의한 메소드 이름도 반드시 함께 변경해야 한다. 그렇지 않으면 애플리케이션을 시작하는 시점에 오류가 발생한다.
이렇게 애플리케이션 로딩 시점에 오류를 인지할 수 있는 것이 스프링 데이터 JPA의 매우 큰 장점이다.
JPA에서는 @NamedQuery 어노테이션을 제공한다 @NamedQuery는 Entity 클래스 내에서 JPQL 쿼리를 작성할 수 있고 정적 쿼리로 애플리케이션 로딩 시점에 JPQL 문법을 체크하고 미리 파싱하기 때문에 요류를 빨리 확인 할 수 있다.
@Entity
@NamedQuery(
name = "Member.findByUsername",
query = "select m from Member m where m.username = :username"
)
public class Member {
@Id @GeneratedValue
@Column(name = "member_id")
private Long id;
private String username;
private int age;
.....
}
public interface MemberRepository extends JpaRepository<Member, Long> {
// @Query(name = "Member.findByUsername") 생략 가능
List<Member> findByUsername(@Param("username") String username);
}
도메인 클래스 + .(점) + 메소드 이름
으로 NamedQuery
쿼리를 찾아서 실행한다. (그렇기 때문에 @Query 생략이 가능하다.)@Param
어노테이션을 사용해 파라미터를 지정해줘야 한다.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);
@Query("select m.username from Member m")
List<String> findUsernameList();
@Query("select new com.study.datajpa.dto.MemberDto(m.id, m.username, t.name) " +
"from Member m join m.team t")
List<MemberDto> findMemberDto();
}
@Query 어노테이션에 직접 JPQL 쿼리를 작성하면 엔티티에서 @NamedQuery 어노테이션으로 작성할 필요 없이 JpaRepository 안에서 바로 JPQL 쿼리 사용이 가능하다.
실무에서는 메소드 이름으로 쿼리 생성 기능은 파라미터가 증가하면 메서드 이름이 매우 지저분해진다. 따라서
Qeury
기능을 사용하게 된다. -스프링 데이터 JPA 김영한-
select m from Member m where m.username = ?0 //위치 기반
select m from Member m where m.username = :name //이름 기반
코드 가독성과 유지보수를 위해 이름 기반 파라미터 바인딩을 사용하자
Collection
타입으로 in
절 지원
@Query("select m from Member m where m.username in :names ")
List<Member> findByNames(@Param("names") Collection<String> names);
스프링 데이터 JPA는 유연한 반환 타입을 지원한다.
List<Member> findListByUsername(String username);
Member findMemberByUsername(String username);
Optional<Member> findOptionalByUsername(String username);
void | Denotes no return value. |
---|---|
Primitives | Java primitives. |
Wrapper types | Java wrapper types. |
T | A unique entity. Expects the query method to return one result at most. If no result is found, null is returned. More than one result triggers an IncorrectResultSizeDataAccessException . |
Iterator<T> | An Iterator . |
Collection<T> | A Collection . |
List<T> | A List . |
Optional<T> | A Java 8 or Guava Optional . Expects the query method to return one result at most. If no result is found, Optional.empty() or Optional.absent() is returned. More than one result triggers an IncorrectResultSizeDataAccessException . |
Option<T> | Either a Scala or Vavr Option type. Semantically the same behavior as Java 8’s Optional , described earlier. |
Stream<T> | A Java 8 Stream . |
Streamable<T> | A convenience extension of Iterable that directy exposes methods to stream, map and filter results, concatenate them etc. |
Types that implement Streamable and take a Streamable constructor or factory method argument | Types that expose a constructor or ….of(…) /….valueOf(…) factory method taking a Streamable as argument. See Returning Custom Streamable Wrapper Types for details. |
Vavr Seq , List , Map , Set | Vavr collection types. See Support for Vavr Collections for details. |
Future<T> | A Future . Expects a method to be annotated with @Async and requires Spring’s asynchronous method execution capability to be enabled. |
CompletableFuture<T> | A Java 8 CompletableFuture . Expects a method to be annotated with @Async and requires Spring’s asynchronous method execution capability to be enabled. |
Slice<T> | A sized chunk of data with an indication of whether there is more data available. Requires a Pageable method parameter. |
Page<T> | A Slice with additional information, such as the total number of results. Requires a Pageable method parameter. |
............... |
List.empty()
, Optional.empty()
등null
반환 javax.persistence.NonUniqueResultException
예외 발생