백엔드 개발자

[#1] 스프링 데이터 JPA 본문

스프링/스프링 데이터 JPA

[#1] 스프링 데이터 JPA

임잠탱 2023. 9. 10. 21:55

공통 인터페이스

  • CRUD에 해당하는 find, delete 등 많이 쓰이는데 항상 같은 코드를 반복하게 된다.
  • JpaRepository
    • 이것을 우리가 사용할 repository 인터페이스에서 JpaRepository<클래스, 클래스의 pk 자료형> 을 상속받으면 스프링 데이터 JPA에서 구현 클래스를 만들어 인터페이스를 구현한 프록시 객체를 만들어 준다.
    • 우리는 인터페이스를 직접 구현하지 않고 find, findAll 등 지원하는 다양한 메서드를 사용할 수 있다.

메서드 쿼리

  • 공통 인터페이스 말고 우리 도메인에 특화된 쿼리문도 필요할 것이다.
  • 이때 정해진 규칙에 맞춰 메서드 이름을 작성하면 우리 도메인에 해당하는 쿼리로 구현체를 만들어준다.
    • findByName 을 하면 name으로 찾아오는 쿼리를 자동 구현해 줄 것이다.
    • And 로 여러개의 조건을 추가할 수도 있고, GreaterThan으로 값을 비교할 때 ≥(이상) 을 나타낼 수 있다.
    • findById 같은 메서드에서 find 와 By 사이에 메서드 설명문을 아무거나 넣을 수도 있다.
    • 엔터티에 없는 속성을 찾아오는 메서드를 작성하면 애플리케이션 실행시점에 오류를 잡아준다.
    • 조건이 많아질수록 메서드 이름이 계속 길어진다.
  • https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#repositories.query-methods.query-creation

결과값을 Dto로 받아오기

  • JPQL 쿼리문으로 Dto로 받아오려면 select에서 Dto를 받을 수 있는데, 패키지 경로까지 다 써서

    new로 객체를 새로 생성해주어야한다.

    ex ) select new {{패키지경로}}.myDto(m.id, m.name) from Member m

파라미터 바인딩

  • JPQL에서 파라미터를 :name 형식으로 넣어주는데 in :names 로 파라미터에 컬렉션을 넣어줄 수 있다.

제공하는 메서드 외에 추가 메서드를 생성하려면?

  • 메서드 위에 바로 @Query 어노테이션으로 jpql을 작성할 수 있다.
  • 혹은 우리가 인터페이스를 직접 구현할 수 있다.
    • 그런데 한 가지 메서드를 추가하기 위해 인터페이스를 직접 구현하려면 implement 하면 jpa가 자동으로 구현체를 생성해주었던 메서드들도 전부 구현해 주어야 한다.
    • 그 대신 새로운 인터페이스를 만들고 추가할 메서드들을 정의하여 직접 구현하고 상속받으면 기존 인터페이스는 jpa가 자동으로 구현해주고 내가 원하는 메서드만 추가로 정의하여 사용할 수 있다.
      • 이 경우 구현체는 인터페이스이름 + Impl을 적용하는 것이 규칙이다.
  • 인터페이스와 분리하여 아예 새로운 class를 만들어 사용할 수도 있다.
    • 한 인터페이스로 모두 사용하려면 너무 커지고 복잡해 질 수 있다.
    • 비지니스 로직에 따라 기능들을 분리하여 상황에 따라 새로운 클래스를 만들어 사용할 수 있다.

페이징

  • 기존 메서드에서 매개변수로 Pagable 하나만 추가해 주면 된다.

    • 요청은 PageRequest로 만들어 전달해준다.
  • Pagable은 시작 페이지, 사이즈, 정렬(선택) 로 구성할 수 있다.

  • 반환 타입을 Page, Slice 로 나눌 수 있는데

    • Page 는 content와 totalCount등을 반환해준다.
    • Slice는 요청한 사이즈 보다 +1하여 데이터가 더 있는지 확인해준다.
      • 데이터가 더 있을 때 더보기 버튼같은 것을 보여주면 Slice를 이용해 구현할 수 있다.
  • 반환 타입에 따라 count 쿼리를 날리거나 하는 변화가 있는데 아예 List로 반환할 수도 있다

    • 페이징 역할을 하는 것이기 때문에 limit관련해서만 페이징 해주게 된다.
  • total 카운트 쿼리는 모든 데이터를 조회해야하기 때문에 성능에 문제가 될 수 있다.

    • 조인이 일어나는 쿼리에서 카운트 쿼리도 조인을 하여 count문을 실행하게 되는데 조인이 필요없는

      상황에서 성능만 느려질 수 있다.

    • 이때 일반 쿼리와 카운트 쿼리를 분리하여 사용할 수 있다.

    • @Query 어노테이션으로 jpql문을 작성할 때 countQuery 옵션에 따로 쿼리문을 작성해 준다.

  • Page<엔티티>로 받아온 값 Page로 변환하여 매핑하기

    • Page dtos = page.map(m → new MemberDto());

벌크성 쿼리

  • 여러 객체에 대해 한 번에 모두 업데이트 하는 쿼리

  • 기존 jpa는 객체를 가져와서 수정을 해주면 영속성컨테이너에서 업데이트 되는 방식이다.

  • 한 번에 여러 객체에 대해 업데이트를 하기 위해 바로 데이터베이스에 업데이트 시킨다.

    • 기존 sql을 사용해서 update를 진행하는 것과 똑같은데 jpa에서는 객체 중심으로 하나씩 가져와서

      변경해주었기 때문에 여기서는 바로 데이터베이스에 업데이트 해준다는 것이 다르다.

    • 영속성 컨텍스트를 안거치고 바로 데이터베이스에 업데이트 되기 때문에 영속성 컨텍스트에는 반영이 안된 것에 주의해주어야 한다.

  • select문과 달리 update문을 사용하여 executeUpdate를 실행해주기 위해 @Modifying을 추가해 주어야 한다.

    • @Modifying(clearAutomatically = true) 옵션을 추가해 주면 벌크업 쿼리를 실행한 후 영속성 컨텍스트를 clear해주기 때문에 위에 언급한 동기화 문제를 해결할 수 있다.

EntityGraph

  • 기존 fetch 조인을 쿼리문으로 직접 작성하던걸 어노테이션으로 지원하는 기능이다.
  • 메서드 쿼리에서도 fetch 조인을 쓰기 위해 쿼리문을 써줘야 했는데 쿼리문 대신
    • @EntityGraph(attributePaths = {”fetch조인 대상”})을 쓰면 fetch 조인한 결과를 얻을 수 있다.
    • fetch조인 대상에는 반환 객체에 포함된 fetch 조인 할 연관관계 대상의 이름을 쓰면 된다.

@QueryHints

  • (value = @QueryHint(name = “org.hibernate.readOnly”, value = “true”))
  • 변경할 목적 없이 그냥 조회만 하고 싶을 때 사용할 수 있다.
  • 성능 최적화 목적이다.
  • jpa는 변경감지를 위해 조회를 하면 영속성 컨텍스트에 원본과 복사본까지 가져오게 되는데 변경할 일이 없는 경우에는 이 어노테이션을 사용해서 성능 최적화를 할 수 있다.

'스프링 > 스프링 데이터 JPA' 카테고리의 다른 글

[#2] 스프링 데이터 JPA  (0) 2023.09.10
Comments