[JPA] 데이터 JPA(1)
본 포스트는 Inflearn
의 김영한님 강의를 바탕으로 작성했습니다.
@Repository 기능
@Repository는 2가지 기능을 제공한다. 첫번째는 이 Annotation이 붙은 클래스를 스프링 빈으로 등록한다. 두번째는 JPA 예외를 스프링 예외로 변환해준다. 데이터를 직접 접근하는 Repository 계층 구현 기술에 Service 계층이 직접 의존하는 것은 좋은 설계라고 할 수 없다. 이는 예외 처리에도 동일하게 적용된다. @Repository를 붙이면 데이터 접근 계층의 예외를 추상화해서 Service 계층에 넘김으로써 데이터 접근 계층의 예외가 바뀌더라도 코드를 변경하지 않고 동일하게 사용할 수 있다.
공통 인터페이스
Spring data JPA
를 제대로 이해하기 위해서는 공통 인터페이스에 대해서 알 필요가 있다.
공통 인터페이스는 위와 같은 구조로 이루어져 있다. 이 인터페이스를 개발자가 직접 구현할 필요가 없다. Spring data JPA 가 구현 클래스를 우리 대신 생성해서 넣어준다. 때문에 우리는 그냥 가져다 쓰면 된다. ^.^
메소드 이름으로 쿼리 자동생성
Spring data JPA는 repository에 작성한 메소드 이름을 분석해서 JPQL 쿼리를 실행해준다. 순수한 JPA를 사용했을 때의 쿼리와 Spring data JPA 를 사용했을 때 코드를 비교해보자.
아래 코드는 순수 JPA를 사용했을 때 코드이다.
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();
}
아래 코드는 Spring Data JPA를 사용했을 때의 코드이다.
public List<Member> findByUsernameAndAgeGreaterThan(String username, int age);
힘의 차이가 확실히 느껴진다.
위와 같이 단순한 쿼리에 대해서 Spring Data JPA를 사용하면 생산성이 대폭 증가한다.
하지만 장점만 존재하지는 않는다. 쿼리 조건이 많아질수록 메서드 이름도 같이 늘어난다. 때문에 복잡한 조건의 쿼리는 다른 방법으로 해결해야 한다.
이 방법도 뒤에서 소개하겠다. 메서드 이름 규칙은 Spring 공식 페이지에 잘 나와있다.
Spring Data JPA의 NamedQuery
순수 JPA에서 namedQuery를 작성하려면 Entity에 직접 작성해야 하거나, XML 파일을 통해서 작성해야 했다. 첫번째는 Entity가 굉장히 지저분해진고 XML은 따로 관리해야 했기 때문에 불편했었다. Spring Data JPA는 @Query를 통해서 Repository에 직접 작성할 수 있다.
아래 예제 코드를 보자.
@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);
위와 같이 작성하면 된다. namedQuery의 장점은 컴파일 시점에 쿼리를 파싱해서 체크하기 때문에 문법 오류를 발견할 수 있는 것인데 @Query로 작성한 쿼리도 namedQuery로 간주되기 때문에 굉장히 유용하다.
반환 타입 지정
Spring Data JPA는 유연하게 반환 타입을 지원한다. 그렇기 때문에 어떻게 작동하는지 잘 이해할 필요가 있다.
조회 결과가 여러개 이거나, 없다면 어떻게 될까? 컬렉션의 경우 결과가 없으면 빈 컬렉션을 반환한다. 하지만 Entity와 같이 타입을 단건으로 찝은 경우에는 결과가 없으면 null
이 반환된다. 이 차이를 인지하고 있어야 한다.
그리고 단건 반환 타입을 설정한 경우 내부적으로 getSingleResult()
를 호출하기 때문에 2개 이상의 값이 나오면 NoResultException
이 발생하는데 Spring Data JPA에서 예외를 catch해서 null로 반환한다. 동작방식을 잘 이해하도록 하자!!
참고 사이트 출처
- https://www.inflearn.com/course/%EC%8A%A4%ED%94%84%EB%A7%81-%EB%8D%B0%EC%9D%B4%ED%84%B0-JPA-%EC%8B%A4%EC%A0%84
더 자세한 내용은 김영한님 강의를 참고하자!