[Spring] 쿼리 메소드, JPQL, QueryDSL

mingsso·2023년 6월 13일
0

SpringBoot

목록 보기
7/11

1️⃣ 쿼리 메소드

Spring Data JPA를 이용하면, 리포지토리에 JpaRepository를 상속하여 다양한 CRUD 메소드를 사용할 수 있음

하지만 JpaRepository의 기능만으로는 실무의 모든 기능을 구현할 수 없기 때문에 로직에 맞는 함수를 따로 정의해줘야 하며, 이때 쿼리 메소드를 사용함
메소드 이름만으로 쿼리를 작성할 수 있음

쿼리 메소드의 생성

"주제" + By + "서술어"

  • 쿼리 메소드의 이름은 동작을 결정하는 주제와 검색 및 정렬 조건을 지정하는 서술어로 구성됨
  • 주제 부분에서 사용할 수 있는 대표적인 키워드는 find..By, exists..By, count..By, delete..By 등이 있음
  • 서술어 부분에서 And나 Or를 사용해 조건을 확장할 수도 있음
  • 서술어에서는 엔티티에서 관리하고 있는 필드만 참조할 수 있음
public interface BoardRepository extends CrudRepository<Board, Long> {
	// Board 엔티티에서 title 변수 값만 조회
    List<Board> findByTitle(String searchKeyword);
}
// 추가된 메소드를 테스트 
@SpringBootTest
public class QueryMethodTest {
    @Autowired
    private BoardRepository boardRepo;

    @BeforeEach
    public void dataPrepare() {
        for (int i = 1; i <= 200; i++) {
            Board board = new Board();
            board.setTitle("테스트 제목 " + i);
            board.setWriter("테스터");
            board.setContent("테스트 내용 " + i);
            board.setCreateDate(new Date());
            board.setCnt(0L);
            boardRepo.save(board);
        }
    }

    @Test
    public void testFindByTitle(){
        List<Board> boardList = boardRepo.findByTitle("테스트 제목 10");
        System.out.println("검색 결과");
        for (Board board : boardList) {
            System.out.println("---> " + board.toString());
        }
    }

}

쿼리 메소드를 통해 간단하게 필요한 객체를 조회할 수 있지만, 조금 더 복잡한 조건을 사용하려면 메소드의 길이가 증가하게 된다는 단점이 있음
이러한 단점을 해결하기 위해 JPQL을 사용함



2️⃣ JPQL

JPA Query Language, JPA에서 사용할 수 있는 쿼리

복잡한 조건을 메소드로 표현하기 어려울 수 있기 때문에, JPQL을 사용하여 직접 쿼리문을 작성해 객체를 조회할 수 있음

객체를 대상으로 하는 쿼리문이며 SQL을 추상화해서 사용하기 때문에, 어떤 DB를 사용하더라도 문제없이 사용할 수 있음
@Query("쿼리문")으로 사용함

@Query("SELECT p FROM Product p WHERE p.name = :name")
List<Product> findByNameParam(@Param("name") String name);
// :name은 @Param("name")을 사용해서 넣어줄 수 있음 


하지만 직접 문자열로 쿼리를 입력하기 때문에, 컴파일 시점에 에러를 잡지 못하고 런타임 에러가 발생할 수 있다는 단점이 있음
이러한 단점을 해결하기 위해 QueryDSL을 사용함



3️⃣ QueryDSL

쿼리문을 소스코드를 사용해서 작성함

  • QueryDSL은 엔티티 클래스와 Q도메인이라는 쿼리 타입의 클래스를 자체적으로 생성해서 메타데이터로 사용함

    QClass
    QueryDSL은 컴파일 단계에서 엔티티를 기반으로 QClass를 생성하는데, JPAAnnotationProcessor가 컴파일 시점에 작동해서 @Entity 등의 어노테이션을 찾아 해당 파일을 분석해서 QClass를 만듦

    QClass는 Entity와 형태가 똑같은 Static Class로, QueryDSL은 쿼리를 작성할 때 QClass를 기반으로 쿼리를 실행함

  • 장점
    • IDE가 제공하는 코드 자동 완성 기능을 사용할 수 있음
    • 문법 오류 시 컴파일 에러가 발생, 가독성 및 생산성 향상
    • 동적으로 쿼리를 생성할 수 있음

QueryDSL 사용하기

@PersistenceContext
EntityManager entityManager;

@Test
void queryDslTest() {
	// QueryDSL을 사용하기 위해서는 JPAQuery 객체를 사용함
    // JPAQuery는 엔티티 매니저를 활용해 생성함
	JPAQuery<Product> query = new JPAQuery(entityManager);
	QProduct qProduct = QProduct.product;
	
    // 빌더 형식으로 쿼리를 작성함 
    // List 타입으로 값을 리턴받기 위해서는 fetch()를 사용해야 함 
	List<Product> productList = query
		.from(qProduct)
        .where(qProduct.name.eq("펜"))
        .orderBy(qProduct.price.asc())
        .fetch();

	for (Product product : productList) {
		System.out.println("Product Number : " + product.getNumber());
		System.out.println("Product Name : " + product.getName());
		System.out.println("Product Price : " + product.getPrice());
		System.out.println("Product Stock : " + product.getStock());
	}
}






참고자료

도서 '스프링부트 핵심 가이드'
https://binco.tistory.com/entry/Spring-Data-JPA-%EC%BF%BC%EB%A6%AC%EB%A9%94%EC%84%9C%EB%93%9C?category=1036292
https://velog.io/@simgyuhwan/%EC%BF%BC%EB%A6%AC-%EB%A9%94%EC%86%8C%EB%93%9C-JPQL-Querydsl-%EC%9A%94%EC%95%BD
https://yeoncoding.tistory.com/369

profile
🐥👩‍💻💰

0개의 댓글