Framework & Library/Spring

[Spring / JPA] JPQL을 사용한 코드 리팩토링

마볼링 2023. 7. 7. 14:38
스프링 JPA는 다양한 쿼리 방법을 지원한다.
그 중 JPQL을 쓴 내용을 정리해보았다.

 

📕 JPQL (Java persistence Query Language)

📗 JPQL 이란?

  • 테이블 대상으로 쿼리하는 것이 아니라 엔티티 객체를 대상으로 쿼리한다.
  • SQL과 비슷한 문법을 가지며, JPQL은 결국 SQL로 변환된다.
  • JPA에서 제공하는 메소드 호출만으로 섬세한 쿼리 작성이 어렵다는 문제에서 JPQL이 탄생된 것이다.

 

📗 특징

  • 객체를 검색하는 객체지향 쿼리
  • SQL을 추상화 했기 때문에 특정 벤더에 종속적이지 않음
  • JPA는 JPQL을 분석하여 SQL을 생성한 후 DB에서 조회

 

📕 프로젝트 중 활용(로스트아크 숙제 체크)

📗 엔티티 구조

[Content] - 일일 숙제와 주간 숙제를 나누기 위해 추상클래스로 생성

@Entity
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@Data
public abstract class Content {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "content_id")
    private long id;

    @Enumerated(EnumType.STRING)
    private Category category; // 일일 숙제, 주간 숙제 분류

    private String name;

    private double level; //컨텐츠 레벨

}

 

[DayContent] - 일일 컨텐츠 (카오스 던전, 가디언 토벌등)

@Entity
@Getter
public class DayContent extends Content{

    @Enumerated(EnumType.STRING)
    private Category dayContentCategory; // 가디언 토벌, 카오스 던전 분류

    private double shilling; //실링

    private double honorShard; //명파

    private double leapStone; //돌파석

    private double destructionStone; //파괴석

    private double guardianStone; //수호석

    private double jewelry; //1레벨 보석

    private double gold; //평균 골드

}

 

📗 기존 코드

[ContentRepository]

DayContent findTop1ByLevelLessThanEqualOrderByLevelDesc(double level);
  • JPA 쿼리 메소드를 이용하여 만든 메서드이다
  • 특정 레벨이하의 컨텐츠를 정렬해서 하나의 데이터만을 가져온다.
  • 몇 가지 기능만을 넣었는데도 메소드명이 너무 길어 수정하였다.

 

📗 변경 코드

[ContentRepository]

@Query("select c from DayContent c " +
        "where c.level <= :level " +
        "and c.dayContentCategory = :contentCategory " +
        "order by c.level desc")
List<DayContent> findDayContentByLevel(
        @Param("level") double level, @Param("contentCategory") Category category);
  • DayContent 중 특정 레벨 이하, 컨텐츠 이름 분류(카오스던전, 가디언토벌), 레벨 순으로 정렬하여 가져온다.
  • JPQL은 limit를 지원하지 않아 리스트로 반환하고 서비스 단에서 하나를 선택하였다.

 

[ContentService]

public Map<Category, DayContent> getDayContentByLevel(double level) {
    DayContent chaosContent = contentRepository.findDayContentByLevel(level, Category.카오스던전).get(0);
    DayContent guardianContent = contentRepository.findDayContentByLevel(level, Category.가디언토벌).get(0);

    Map<Category, DayContent> dayContentMap = new HashMap<>();
    dayContentMap.put(Category.카오스던전, chaosContent);
    dayContentMap.put(Category.가디언토벌, guardianContent);
    return dayContentMap;
}
  • 쉽게 사용하기 위해 Map으로 만들어서 리턴하였다.