[spring] Spring Data JPA 기본정리

devyu·2021년 3월 14일
5

Spring Data JPA

public interface MemberRepository extends JpaRepository<Member, Long> {
 
}
  • JpaRepository 인터페이스는 공통 CRUD를 제공하며 제네릭은 <엔티티 타입, 식별자 타입> 으로 설정한다.
  • Spring Data JPA가 스스로 인터페이스에 대한 Proxy 객체(구현 클래스)를 생성하여 MemberRepository 를 구현하기 때문에 인터페이스만으로 JPA가 동작하도록 설계되어 있다.
  • Spring Data JPA가 적용된 인터페이스는 Component-Scan 대상이므로 @Repository 애노테이션이 생략 가능하다.

Spring Data JPA가 제공하는 기본 메서드

save(S) : 새로운 엔티티는 저장하고 이미 있는 엔티티는 병합한다.
delete(T) : 엔티티 하나를 삭제한다. 내부에서 EntityManager.remove() 호출
findById(ID) : 엔티티 하나를 조회한다. 내부에서 EntityManager.find() 호출
getOne(ID) : 엔티티를 프록시로 조회한다. 내부에서 EntityManager.getReference() 호출
findAll(…) : 모든 엔티티를 조회한다. 정렬( Sort )이나 페이징( Pageable ) 조건을 파라미터로 제공할
수 있다


Query Method 방식(메서드 이름을 통한 쿼리 생성)

public interface MemberRepository extends JpaRepository<Member, Long> {
    // Spring Data JPA는 메소드 이름을 분석하여 JPQL을 생성 및 실행한다.
    // 회원명이 username이며 나이가 age보다 큰 회원을 조회
    List<Member> findByUsernameAndAgeGreaterThan(String username, int age);
}
MemberRepositoryfindByUsernameAndAgeGreaterThan 메서드를 실행하면 실제로 실행되는 쿼리

select member0_.member_id as member_i1_0_, member0_.age as age2_0_, member0_.team_id as team_id4_0_, member0_.username as username3_0_ from member member0_ where member0_.username='AAA' and member0_.age>15;

  • 기본으로 제공되는 메서드 이외에도 Query Method 기능을 통해 보다 상세한 쿼리 사용이 가능하다.
  • Entity 의 필드명에 의존적인 방식이라 필드명이 변경되면 인터페이스에 정의한 메서드 명도 같이 변경되어야 한다.(애플리케이션 로딩 시점에 오류를 인지할 수 있음)
  • Spring Data JPA가 제공하는 Query Method의 기능 참조(https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#jpa.query-methods.query-creation)

NamedQuery 방식

@Entity
@NamedQuery(
        name = "Member.findByUsername",
        query = "select m from Member m where m.username = :username"
)
public class Member {
	private String username;
}
public interface MemberRepository extends JpaRepository<Member, Long> {
    @Query(name = "Member.findByUsername")
    List<Member> findByUsername(@Param("username") String username);
}
  • Entity에서 query를 직접 생성하는 방식
  • 기본적으로 JpaRepository 인터페이스의 제네릭의 엔티티 타입 + . + 메소드명으로 NamedQuery를 찾도록 설계되어 있어서 Entity에서 @namedQueryname과 일치하다면 @Query 애노테이션은 생략할 수 있다.
  • @NamedQuery의 가장 큰 장점은 애플리케이션 loading시점에서 Query를 파싱해서 검증하기 때문에 쿼리 문법 오류를 개발자가 발견하기 용이하다.

@Query repository 직접 정의 방식

public interface MemberRepository extends JpaRepository<Member, Long> {
    // Query repository 직접 정의 방식
    @Query("select m from Member m where m.username= :username and m.age = :age")
    List<Member> findMember(@Param("username") String username, @Param("age") int age);
}
  • @NamedQuery 방식처럼 애플리케이션 loading시점에 JPQL 문법 오류를 발견하기 쉽다.
  • 실무에서 가장 많이 사용되는 방식

@Query 결과값 DTO객체 바인딩하기

public interface MemberRepository extends JpaRepository<Member, Long> {
    // 객체DTO에 조회값 바인딩 하기
    @Query("select new com.study.datajpa.dto.MemberDto(m.id, m.username, t.name) from Member m join m.team t")
    List<MemberDto> findMemberDto();
}
@Data
@AllArgsConstructor // DTO에 바인딩할 필드는 생성자 작업이 필수
public class MemberDto {

    private Long id;
    private String username;
    private String teamName;

}
  • 해당 인터페이스는 Member 엔티티 타입을 전용으로 사용하므로 다른 DTO객체에 결과값을 바인딩해서 반환하려면 new 명령어와 DTO객체의 패키지 경로, 바인딩 필드 생성자 파라미터@Query 쿼리 안에 직접 입력해주어야 한다.

profile
코딩요리사

0개의 댓글