[스프링 DB 2편] #6. 데이터 접근 기술 - 스프링 데이터 JPA #590
Develop-KIM
started this conversation in
동환
Replies: 0 comments
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
스프링 데이터 JPA 주요 기능
스프링 데이터 JPA는 JPA를 편리하게 사용할 수 있도록 도와주는 라이브러리이다.
대표적인 기능
공통 인터페이스 기능
JpaRepository인터페이스를 통해서 기본적인 CRUD 기능 제공한다.CrudRepository에서fineOne()->findById()로 변경되었다.JpaRepository
JpaRepository인터페이스를 인터페이스 상속 받고, 제네릭에 관리할<엔티티, 엔티티ID>를 주면 된다.그러면
JpaRepository가 제공하는 기본 CRUD 기능을 모두 사용할 수 있다.스프링 데이터 JPA가 구현 클래스를 대신 생성

JpaRepository인터페이스만 상속받으면 스프링 데이터 JPA가 프록시 기술을 사용해서 구현 클래스를 만들어준다.그리고 만든 구현 클래스의 인스턴스를 만들어서 스프링 빈으로 등록한다.
쿼리 메서드 기능
스프링 데이터 JPA는 인터페이스에 메서드만 적어두면, 메서드 이름을 분석해서 쿼리를 자동으로 만들고 실행해주는 기능을 제공한다.
순수 JPA 리포지토리
순수 JPA를 사용하면 직접 JPQL을 작성하고, 파라미터도 직접 바인딩 해야 한다.
스프링 데이터 JPA
물론 그냥 아무 이름이나 사용하는 것은 아니고 다음과 같은 규칙을 따라야 한다.
스프링 데이터 JPA가 제공하는 쿼리 메소드 기능
find…By,read…By,query…By,get…ByfindHelloBy처럼 ...에 식별하기 위한 내용(설명)이 들어가도 된다.count…By반환타입longexists…By반환타입booleandelete…By,remove…By반환타입longfindDistinct,findMemberDistinctByfindFirst3,findFirst,findTop,findTop3JPQL 직접 사용하기
@Query와 함께 JPQL을 작성하면 된다.이때는 메서드 이름으로 실행하는 규칙은 무시된다.
스프링 데이터 JPA 적용1
설정
스프링 데이터 JPA는
spring-boot-starter-data-jpa라이브러리를 넣어주면 된다.build.gradle 추가
그런데 이미 앞에서 JPA를 설정하면서
spring-boot-starter-data-jpa라이브러리를 넣어주었다.여기에는
JPA, 하이버네이트, 스프링 데이터 JPA(spring-data-jpa), 그리고 스프링 JDBC 관련 기능도 모두 포함되어 있다.따라서 스프링 데이터 JPA가 이미 추가되어있으므로 별도의 라이브러리 설정은 하지 않아도 된다.
스프링 데이터 JPA 적용
SpringDataJpaItemRepository
JpaRepository인터페이스를 인터페이스 상속 받으면 기본적인 CRUD 기능을 사용할 수 있다.그런데 이름으로 검색하거나, 가격으로 검색하는 기능은 공통으로 제공할 수 있는 기능이 아니다.
따라서 쿼리 메서드 기능을 사용하거나
@Query를 사용해서 직접 쿼리를 실행하면 된다.데이터를 조건에 따라 4가지로 분류해서 검색한다.
동적 쿼리를 사용하면 좋겠지만, 스프링 데이터 JPA는 동적 쿼리에 약하다. 이번에는 직접 4가지 상황을 스프링 데이터JPA로 구현해보자.
그리고 이 문제는 이후에 Querydsl에서 동적 쿼리로 깔끔하게 할 수 있다.
findAll()
코드에는 보이지 않지만
JpaRepository공통 인터페이스가 제공하는 기능이다.모든
Item을 조회한다. 다음과 같은 JPQL이 실행된다.select i from Item ifindByItemNameLike()
이름 조건만 검색했을 때 사용하는 쿼리 메서드이다.
다음과 같은 JPQL이 실행된다.
select i from Item i where i.name like ?findByPriceLessThanEqual()
가격 조건만 검색했을 때 사용하는 쿼리 메서드이다.
다음과 같은 JPQL이 실행된다.
select i from Item i where i.price <= ?findByItemNameLikeAndPriceLessThanEqual()
이름과 가격 조건을 검색했을 때 사용하는 쿼리 메서드이다.
다음과 같은 JPQL이 실행된다.
select i from Item i where i.itemName like ? and i.price <= ?findItems()
메서드 이름으로 쿼리를 실행하는 기능은 다음과 같은 단점이 있다.
메서드 이름으로 쿼리를 실행하는 기능은 간단한 경우에는 매우 유용하지만, 복잡해지면 직접 JPQL 쿼리를 작성하는 것이 좋다.
@Query애노테이션을 사용하면 된다.@Param("itemName")애노테이션을 사용하고, 애노테이션의 값에 파라미터 이름을 주면 된다.스프링 데이터 JPA 적용2
JpaItemRepositoryV2
의존관계와 구조
ItemService는ItemRepository에 의존하기 때문에ItemService에서SpringDataJpaItemRepository를 그대로 사용할 수 없다.ItemService가SpringDataJpaItemRepository를 직접 사용하도록 코드를 고치면 되겠지만우리는
ItemService코드의 변경없이ItemService가ItemRepository에 대한 의존을 유지하면서 DI를 통해 구현 기술을 변경하고 싶다.조금 복잡하지만, 새로운 리포지토리를 만들어서 이 문제를 해결해보자.
여기서는
JpaItemRepositoryV2가ItemRepository와SpringDataJpaItemRepository사이를 맞추기 위한 어댑터 처럼 사용된다.클래스 의존 관계

JpaItemRepositoryV2는ItemRepository를 구현한다. 그리고SpringDataJpaItemRepository를 사용한다.런타임 객체 의존 관계

itemServicejpaItemRepositoryV2springDataJpaItemRepository(프록시 객체)이렇게 중간에서
JpaItemRepository가 어댑터 역할을 해준 덕분에ItemService가 사용하는ItemRepository인터페이스를 그대로 유지할 수 있고 클라이언트인ItemService의 코드를 변경하지 않아도 되는 장점이 있다.save()
repository.save(item)스프링 데이터 JPA가 제공하는
save()를 호출한다.update()
스프링 데이터 JPA가 제공하는
findById()메서드를 사용해서 엔티티를 찾는다.그리고 데이터를 수정한다.
이후 트랜잭션이 커밋될 때 변경 내용이 데이터베이스에 반영된다. (JPA가 제공하는 기능이다.)
findById()
repository.findById(itemId)스프링 데이터 JPA가 제공하는
findById()메서드를 사용해서 엔티티를 찾는다.findAll()
데이터를 조건에 따라 4가지로 분류해서 검색한다.
모든 조건에 부합할 때는
findByItemNameLikeAndPriceLessThanEqual()를 사용해도 되고,repository.findItems()를 사용해도 된다.그런데 보는 것 처럼 조건이 2개만 되어도 이름이 너무 길어지는 단점이 있다.
따라서 스프링 데이터 JPA가 제공하는 메서드 이름으로 쿼리를 자동으로 만들어주는 기능과
@Query로 직접 쿼리를 작성하는 기능 중에 적절한 선택이 필요하다.추가로 코드를 잘 보면 동적 쿼리가 아니라 상황에 따라 각각 스프링 데이터 JPA의 메서드를 호출해서 상당히 비효율적인 코드인 것을 알 수 있다.
앞서 이야기했듯이 스프링 데이터 JPA는 동적 쿼리 기능에 대한 지원이 매우 약하다. 이부분은 이후에 Querydsl을 사용해서 개선해보자.
기능을 모두 개발했으니, 설정하고 실행해보자.
SpringDataJpaConfig
SpringDataJpaItemRepository는 스프링 데이터 JPA가 프록시 기술로 만들어주고 스프링 빈으로도 등록해준다.ItemServiceApplication - 변경
SpringDataJpaConfig를 사용하도록 변경했다.테스트를 실행하자
먼저
ItemRepositoryTest를 통해서 리포지토리가 정상 동작하는지 확인해보자. 테스트가 모두 성공해야 한다.애플리케이션을 실행하자
ItemServiceApplication를 실행해서 애플리케이션이 정상 동작하는지 확인해보자.예외 변환
스프링 데이터 JPA도 스프링 예외 추상화를 지원한다.
스프링 데이터 JPA가 만들어주는 프록시에서 이미 예외 변환을 처리하기 때문에
@Repository와 관계없이 예외가 변환된다.주의! - 하이버네이트 버그
하이버네이트
5.6.6~5.6.7을 사용하면Like문장을 사용할 때 다음 예외가 발생한다.스프링 부트
2.6.5버전은 문제가 되는 하이버네이트 5.6.7을 사용한다.java.lang.IllegalArgumentException: Parameter value [\] did not match expected type [java.lang.String (n/a)]build.gradle에 다음을 추가해서 하이버네이트 버전을 문제가 없는
5.6.5.Final로 맞추자.ext["hibernate.version"] = "5.6.5.Final"정리
스프링 데이터 JPA의 대표적인 기능을 알아보았다. 스프링 데이터 JPA는 이 외에도 정말 수 많은 편리한 기능을 제공한다.
심지어 우리가 어렵게 사용하는 페이징을 위한 기능들도 제공한다.
스프링 데이터 JPA는 단순히 편리함을 넘어서 많은 개발자들이 똑같은 코드로 중복 개발하는 부분을 개선해준다.
개인적으로 스프링 데이터 JPA는 실무에서 기본으로 선택하는 기술이다.
All reactions