Programing/JPA

Querydsl vs Criteria API vs QueryMethod vs JPQL 비교

리커니 2023. 7. 20. 18:33
반응형

이전 포스팅에서 Querydsl 을 설정하는 방법을 알아보았습니다.

 

Link : https://aljjabaegi.tistory.com/691

 

Springboot 2.x + queryDSL 설정 방법

JPA를 사용하게 되면 Query method를 사용하면 간단한 조건의 작업들은 가능하지만 복잡한 쿼리로 작성되어야하는 로직의 경우 한계가 있습니다. 물론 어느정도 가능은 하겠지만 query method의 길이가

aljjabaegi.tistory.com

 

이번에는 JPA에서 활용되는 여러가지 방법들과 Querydsl을 비교해 보도록 하겠습니다.

샘플 쿼리에 있는 내용을 Query method, 

 

샘플 쿼리

SELECT CD_ID
     , CD_NM
     , CD_SQNO
 FROM M_OP_CD
WHERE GRP_CD_ID = #{grpCdId}
ORDER BY CD_SQNO ASC

 

1. Query Method

@Repository
public interface CodeRepository extends JpaRepository<M_OP_CD, M_OP_CD_KEY> {

    List<M_OP_CD> findByKeyGrpCdIdOrderByCdSqnoAsc(String grpCdId);
    
}

JPA에서 가장 간단하게 데이터를 조회할 수 있는 방법입니다.

방식만 알면 쉽고 간편하게 사용이 가능하죠. 하지만 복잡한 쿼리의 경우 작성하기 어렵고, 모든 쿼리를 구현하는데는 무리가 있습니다. 간단한 CRUD 작업에만 용이합니다.

 

Link : https://aljjabaegi.tistory.com/678

 

JPA Query Methods 정리

오늘은 JPA에서 간단하게 우리가 원하는 데이터를 조회 할 수 있는 방법중에 하나인 Query Methods 에 대해서 알아보도록 하겠습니다. Keyword Usage JPQL Where and findByColumne1AndColumn2(col1, col2); select ... where

aljjabaegi.tistory.com

 

2. JPQL ( Java Persistence Query Language) and nativeQuery

@Repository
public interface CodeRepository extends JpaRepository<M_OP_CD, M_OP_CD_KEY> {

    @Query(value = "SELECT CD_ID" +
            ", CD_NM" +
            ", CD_SQNO" +
            " FROM M_OP_CD" +
            " WHERE GRP_CD_ID = :grpCdId" +
            " ORDER BY CD_SQNO ASC"
    )
    List<M_OP_CD> findByKeyGrpCdIdOrderByCdSqnoAsc(@Param("grpCdId") String grpCdId);
}

JPQL, nativeQuery를 사용해서 queryMethod의 단점을 보완할 수 있습니다. 위와 같이 @Query 를 사용해 value에 쿼리를 String으로 연결해주시면 됩니다. nativeQuery의 경우 @Query 에 nativeQuery = true 옵션만 주시면 됩니다.

쿼리를 작성해주면 되지만, 보시는데로, String이기 때문에 수정 시 어려움이 있고, 컴파일 시점에 오류를 파악할 수 없습니다.

 

3. CriteriaBuilder

public interface CodeRepository {
    List<M_OP_CD> findByKeyGrpCdIdOrderByCdSqnoAsc(String grpCdId);
}
@Repository
public class CodeRepositoryImpl implements CodeRepository {
    private final EntityManager entityManager;
    
    @Autowired
    public CodeRepositoryImpl(EntityManager entityManager) {
        this.entityManager = entityManager;
    }
    
    @Override
    public List<M_OP_CD> findByKeyGrpCdIdOrderByCdSqnoAsc(String grpCdId) {
        CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
        CriteriaQuery<M_OP_CD> query = criteriaBuilder.createQuery(M_OP_CD.class);
        Root<M_OP_CD> code = query.from(M_OP_CD.class);
        CriteriaQuery<M_OP_CD> criteriaQuery = query.select(code);

        Path<M_OP_CD_GRP> grpCd = code.get("key");
        Predicate predicate = criteriaBuilder.equal(grpCd.get("grpCdId"), grpCdId);

        criteriaQuery = criteriaQuery.where(predicate);
        return entityManager.createQuery(criteriaQuery).getResultList();
}

일단 criteriaBuilder를 사용하면 컴파일 시점에 에러를 잡아주는 장점이 있습니다.

JPQL 처럼 String으로 쿼리를 작성하지 않아도 되고, 좀 더 Java 스럽게 구현을 할 수 있죠.

하지만 간단한 쿼리가 너무 복잡해 졌죠. 간단한 쿼리도 이정도인데, 복잡한 쿼리는...말 안해도 아시겠죠?

 

4. Querydsl

public interface CodeRepository {
    List<M_OP_CD> findByKeyGrpCdIdOrderByCdSqnoAsc(String grpCdId);
}
@Repository
public class CodeRepositoryImpl implements CodeRepository {
    private final JPAQueryFactory jpaQueryFactory;
    
    @Autowired
    public CodeRepositoryImpl(JPAQueryFactory jpaQueryFactory) {
        this.jpaQueryFactory = jpaQueryFactory;
    }
    
    @Override
    public List<M_OP_CD> findByKeyGrpCdIdOrderByCdSqnoAsc(String grpCdId) {
        QM_OP_CD code = QM_OP_CD.m_OP_CD;
        return jpaQueryFactory.selectFrom(code)
                    .where(code.key.grpCdId.eq(grpCdId))
                    .orderBy(code.cdSqno.asc()).fetch();
    }
}

매우 간단하죠? 

Criteria API의 단점은 버리고, 장점과 쿼리의 장점만을 조합한 것 같은 느낌입니다.

 

다양한 DB에서 사용할 수 있고, 쿼리만 작성할 줄 안다면 사용법도 금방 익숙해 질 수 있습니다.

쿼리와 비슷하기 때문에 가독성도 좋고 DB에서 지원하는 기능들을 거의 모두 지원하기 때문에 매우 파워풀 하죠.

써야되는 이유는 명확해졌습니다.

 

다음 포스팅에서는 Querydsl의 다양한 기능에 대해서 알아보겠습니다. 

반응형