본문 바로가기
백엔드/Spring

실전! 스프링 데이터 JPA 내용 정리 - 섹션 4(1)

by 작은소행성 2023. 8. 2.

실무에서 JPA를 사용하는데 개념적인 부분을 집고 넘어가면 좋을 것 같아서 강의를 보게 되었고

인프런 강의를 보고 내용 정리를 해보았다. 

 

 

프로젝트 어노테이션

 

@NoArgsConstructor(AccessLevel.PROTECTED)

엔티티에서 레벨을 protected 까지로 한다

Protected 로 설정하는 이유는 무분별한 객체 생성에 대해 한번 더 체크할 수 있게 한다. 

 

 

그러나 @Builder와 같이 사용하고 싶다면 AllArgsConstructor 와 같이 사용하거나

@Builder

@AllArgsConstructor

 

 

@NoArgsConstructor(access = AccessLevel.PROTECTED)

안에 @Builder를 계속적으로 선언해서 사용해야한다. 

 

@Builder 사용하면 의미있는 객체만 생성할 있게 된다. 

 

 

@ToString 은 객체가 출력될때 바로 값이 출력되는 것이다. 

 

@ToString 에서 연관관계에 있는 값도 출력하면 데이터가 너무 많이 출력될 수 있으니 주의한다. 

가급적이면 연관관계 객체는 사용하지 않는것이 좋다. 

 

 

 

 

 

인터페이스 

스프링 데이터 JPA가 구현 클래스 대신 생성

 

@Repository 어노테이션을 달지 않고 

인터페이스에 repository 이름을 달아서 작성해도 

스프링에서 알아서 프록시 객체를 만들어서 넣어준다. (인터페이스만 잡으면 프록시가 구현 클래스를 만들어서 injection )

 

 

 

 

쿼리 메소드 

메소드 이름으로 쿼리 생성 

public interface MemberRepository extends JpaRepository<Member, Long> {
     List<Member> findByUsernameAndCompany(String username, String company);
}

엔티티의 필드명이 변경되면 인터페이스에 정의한 메서드 이름도 꼭 함께 변경해야 한다.

엔티티 필드명과 인터페이스의 메서드 이름이 동일하지 않으면 애플리케이션을 시작하는 시점에 오류가 발생한다. 

 

스프링 데이터 JPA 공식 문서 참고

https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#repositories.query-methods.query-creation

 

 

 

NamedQuery

@Entity
@NamedQuery(
    name="Member.findByUsername",
    query="select m from Member m where m.username = :username")
public class Member {
 ...
}
@Query(name = "Member.findByUsername")
List<Member> findByUsername(@Param("username") String username);
public interface MemberRepository extends JpaRepository<Member, Long> {
     List<Member> findByUsername(@Param("username") String username);
}

@Query 를 생략하고 메서드 이름만으로 Named 쿼리를 호출할 수 있다

 

** 실무에서 Named Query를 직접 등록해서 사용하는 일은 드물다. 대신 @Query 를 사용해서 Repository 메소드에 쿼리를 직접 정의해서 사용한다. 

 

 

 

@Query, 리포지토리 메소드에 쿼리 정의하기

import org.springframework.data.jpa.repository.Query;


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);

}

실행할 메서드에 정적 쿼리를 직접 작성하므로 이름 없는 Named 쿼리라 할 수 있으며 

JPA Named 쿼리처럼 애플리케이션 실행 시점에 문법 오류를 발견할 수 있다. 

 

** 실무에서는 메소드 이름으로 쿼리 생성 기능은 파라미터가 증가하면 메서드 이름이 매우 지저분해지기 때문에 @Query 기능을 자주 사용하게 된다.

 

 

 

@Query, 값, DTO 조회하기

** 실무에서 많이 사용 

 

사용자 이름 리스트를 가져오고 싶다 라고 했을 때 아래와 같이 사용하면 됨

@Query("select m.username from Member m")
List<String> findUsernameList();

 

Dto 로 조회하고자 할 때

Dto 에 조회하고자 하는 대상 작성

import lombok.Data;

@Data
@AllArgsConstructor
public class MemberDto {
     private Long id;
     private String username;
     private String teamName;
 
//     @AllArgsConstructor 에 대한 내용 
//     public MemberDto(Long id, String username, String teamName) {
//         this.id = id;
//         this.username = username;
//         this.teamName = teamName;
//      }

 }

 

@Query("select new study.datajpa.dto.MemberDto(m.id, m.username, t.name) " +
       "from Member m join m.team t")
List<MemberDto> findMemberDto();

Dto 로 사용할때는 new 를 사용해서 생성자 객체를 사용해야 한다. 

 

 

 

 

 

파라미터 바인딩

위치기반과 이름 기반으로 파라미터 바인딩이 가능하다. 

코드 가독성과 유지보수를 위해 이름 기반 파라미터 바인딩을 사용하는 것이 좋다. 

//이름 기반
 @Query("select m from Member m where m.username = :name") 
//위치 기반
 @Query("select m from Member m where m.username = ?0")

 

컬렉션 파라미터 바인딩

Collection타입으로 in절을 지원해준다.

@Query("select m from Member m where m.username in :names")
List<Member> findByNames(@Param("names") List<String> names);

 

 

반환 타입

컬렉션

List 는 절대 null 이 아닐 수 있게 보장 받는다. 

그래서 null 체크를 따로 하지 않아도 된다. 

@Test
public void returnData(){

    List<Member> result = memberRepository.findByUsername("qwerqwer");
    if(result != null){ // Null 인지 아닌지 체크하는 이 코드를 쓰는것은 비효율적임
    }
    
}

 

단건 조회

Optional 사용

 데이터를 조회할 때 데이터가 있을수도 있고 없을수도 있다면 Optional 을 사용하는것이 맞다.

Member findByUsername(String name); //단건
Optional<Member> findByUsername(String name); //단건 Optional

결과가 없으면 null 이 반환되고 

결과가 2건 이상이면 NonUniqueResultException 예외가 발생한다. 

 

Repository의 쿼리 리턴타입은 스프링 공식 문서에서 더 확인할 수 있다. 

https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#repository-query-return-types

 

 

 

 

 

 

반응형