Search
Duplicate
📒

[스프링 JPA] 03-1. 쿼리 메소드 기능1 ⭐

상태
완료
수업
JPA
주제
JPA
4 more properties
참고

스프링 데이터 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
복사
실제로 발생한 쿼리