참고
스프링 데이터 JPA가 제공하는 쿼리 메서드 기능
NOTE
스프링 데이터 JPA가 제공하는 쿼리 메소드 기능은 3가지가 있다!
1.
메서드 이름으로 쿼리 생성
2.
메서드 이름으로 JPA NamedQuery 호출
3.
@Query 어노테이션을 사용해서 리포지토리 인터페이스에 쿼리 직접 정의
메서드 이름으로 쿼리 생성
순수 JPA 리포지토리
NOTE
public List<Member> findByUserNameAndAgeGreaterThan(String userName, int age) {
return em.createQuery("select m from Member m where m.userName = :userName and m.age > :age")
.setParameter("userName", userName)
.setParameter("age", age)
.getResultList();
}
Java
복사
특정 나이를 넘어서고, 이름이 같은사람을 조회하는 쿼리
•
JPQL을 작성하고, 파라미터를 등록해서 리스트를 뽑아내는 전통적인 방식
스프링 데이터 JPA
NOTE
List<Member> findByUserNameAndAgeGreaterThan(String userName, int age);
Java
복사
특정 나이를 넘어서고, 이름이 같은사람을 조회하는 쿼리
•
스프링 데이터 JPA는 메서드 이름을 분석해서 JPQL을 생성하고 실행한다!
◦
필드명을 틀리면 실행이안됨!
스프링 데이터 JPA가 제공하는 쿼리 메서드 기능
•
조회
◦
find..by, read..By, query..By, get..By
•
COUNT
◦
count..By - 반환타입 long
•
EXISTS
◦
exists..By - 반환타입 boolean
•
삭제
◦
delete..By, remove..By - 반환타입 long
•
DISTINCT
◦
findDistinct, findMemberDistinctBy
•
LIMIT
◦
findFirst3, findFirst, findTop, findTop3
JPA NamedQuery
NOTE
실무에서는 NamedQuery를 직접 등록하지않고, @Query를 사용해서 레포지토리 메서드에 직접 정의해서 사용한다!
순수 JPA 이용
NOTE
1. @NamedQuery 어노테이션으로 Named 쿼리 정의
@NamedQuery(
name="Member.findByUsername",
query="select m from Member m where m.username = :username"
)
public class Member { ... }
Java
복사
•
엔티티에 @NamedQuery를 정의한다.
2. JPA를 직접 사용해서 Named 쿼리 호출
public List<Member> findByUsername(String username) {
return em.createNamedQuery("Member.findByUsername", Member.class)
.setParameter("username", username)
.getResultList();
}
Java
복사
스프링 데이터 JPA 이용
NOTE
1. 스프링 데이터 JPA로 NamedQuery 사용
@Query(name = "Member.findByUsername")
List<Member> findByUsername(@Param("username") String username);
Java
복사
2. 스프링 데이터 JPA로 NamedQuery 호출
•
스프링 데이터 JPA는 선언한 <도메인 클래스 + . + 메서드 이름> 으로 Named 쿼리를 찾아서 실행한다.
@Query, 리포지토리 메소드에 쿼리 정의하기
NOTE
실무에서 많이 쓰이는 방식!, NamedQuery보다 더 편하게 사용이 가능하다!
메서드에 JPQL 쿼리 작성
NOTE
@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();
Java
복사
•
실행할 메서드에 정적 쿼리를 직접 작성하므로 이름 없는 NamedQuery라고 할 수 있다.
•
JPA NamedQuery처럼 어플리케이션 실행 시점에 문법 오류를 발견할 수 있다!
[ 참고]
•
동적쿼리는 Querydsl을 사용해야 한다!
@Query, 값, DTO 조회하기
NOTE
지금까지 엔티티만 조회했었는데, 단순한 값이나 DTO를 조회하는 방식을 사용해보자!
단순한 값 조회
NOTE
@Query("select m.userName from Member m")
List<String> findUserNameList();
Java
복사
public void findUserNameList(){
Member m1 = new Member("AAA", 10);
Member m2 = new Member("BBB", 20);
memberRepository.save(m1);
memberRepository.save(m2);
List<String> userNameList = memberRepository.findUserNameList();
for (String s : userNameList) {
System.out.println("s = " + s);
}
}
Java
복사
결과
s = AAA
s = BBB
•
JPA값 타입(@Embedded)도 이 방식으로 조회할 수 있다.
DTO로 직접조회
NOTE
@Query("select new study.datajpa.dto.MemberDto(m.id, m.userName, t.name) from Member m join m.team t")
List<MemberDto> findMemberDto();
Java
복사
DTO의 패키지이름을 다 적어줘야함
@Data
public class MemberDto {
private Long id;
private String userName;
private String teamName;
public MemberDto(Long id, String userName, String teamName) {
this.id = id;
this.userName = userName;
this.teamName = teamName;
}
}
Java
복사
연습용이라 @Data 사용(실제로는 쓰지말것)
public void findMemberDto(){
Team team = new Team("teamA");
teamRepository.save(team);
Member m1 = new Member("AAA", 10);
m1.setTeam(team);
memberRepository.save(m1);
List<MemberDto> memberDto = memberRepository.findMemberDto();
for (MemberDto dto : memberDto) {
System.out.println("dto = " + dto);
}
}
Java
복사
결과
dto = MemberDto(id=2, userName=AAA, teamName=teamA)
파라미터 바인딩
NOTE
파라미터 바인딩은 위치 기반, 이름 기반두 가지가 있다.
파라미터 바인딩
NOTE
select m from Member m where m.username = ?0 //위치 기반
select m from Member m where m.username = :name //이름 기반(권장)
Java
복사
@Query("select m from Member m where m.username = :name")
Member findMembers(@Param("name") String username);
Java
복사
이름 기반 실제사용 예시
•
위치 기반은 가독성도 떨어지고, 유지보수하기도 어려우므로 이름 기반을 사용하자!
컬렉션 파라미터 바인딩
NOTE
@Query("select m from Member m where m.userName in :names")
List<Member> findByUserNames(@Param("names") Collection<String> names);
Java
복사
Collection 타입으로 in절을 지원한다!
public void findByUserNames(){
Member m1 = new Member("AAA", 10);
Member m2 = new Member("BBB", 20);
memberRepository.save(m1);
memberRepository.save(m2);
List<Member> result = memberRepository.findByUserNames(Arrays.asList("AAA", "BBB"));
for (Member member : result) {
System.out.println("member = " + member);
}
}
Java
복사
결과
member = Member(id=1, userName=AAA, age=10)
member = Member(id=2, userName=BBB, age=20)
select member0_.member_id as member_i1_0_, member0_.age as age2_0_, member0_.team_id as team_id4_0_, member0_.user_name as user_nam3_0_ from member member0_ where member0_.user_name in ('AAA' , 'BBB');
SQL
복사
실제로 발생한 쿼리