본문 바로가기

카테고리 없음

QueryDSL = 쿼리 D게 S쉽네 L리얼

 

한글번역 : 디지게 쉽노 ㅎ

 

서론

Java로 된 서버와 데이터베이스를 연동할 때 흔히들 MyBatis 를 사용한다.

Java 변수를 넘겨서 SQL 문에 채워 DB에 명령을 보내는데,

Java에서 String 을 완성시키는 원초적인 방법은

유지보수도 망치고, 디버깅도 어렵기 때문에,

XML형태를 통해 SQL문을 관리하는 MyBatis도 꽤나 큰 장점을 갖고 있었다.

 

스프링에서는 JPA + 쿼리 조합을 많이 사용하는데, 

JPA는 SQL의 모든 요소를 @어노테이션을 통해 객체화 시킨다.

JPA에서 DB 로 쿼리를 날리있는 방법은 3가지이다:

1. 리포지터리 메서드(스프링 데이터 JPA, 후술)
2. @NamedQuery ( 변수 하나에 SQL문 하나를 미리 할당해놓는 정적 쿼리, 아래 예제)

@NamedQuery(
        name="MemberJPQL.findByName",
        query="select m from MemberJPQL m where m.username = :username"
)


3. @Query ( "select * from someTable" )

여기서 말하는 Query는 JPQL 을 말한다.
MySQL 과 같은 일반적인 쿼리를 쓰려면 NativeQuery 를 써야한다.
밑에서 JPQL에 대한 것도 다뤄보자.

QueryDSL 의 등장

하지만 이것도 저것도 마음에 안드는 개발자들이 수많은 시도 끝에,

누군가가 만들어낸 QueryDSL 하나로 인해

쿼리는 디게 쉬워졌다.

바로 코드를 보자.

public List<Contents> findAll(contentsSearch contentsSearch) {
	MyContents content = MyContents.content;
    MyAuther author = MyAuhor.author;
    
    return query
    		.select(content)
            .from(content)
            .join(content.author, author)
            .where(statusEq(contentsSearch.getContentStatus()),
            		nameLike(contentsSearch.getAutherName()))
            .limit(1000)
            .fetch();
}

private BooleanExpression statusEq(ContentStatus statusCond) {
	if (statusCond == null) {
    	return null;
    }
    return content.status.eq(statusCond);
}

private BooleanExpression nameLike(String nameCond) {
	if (!StringUtils.hasText(nameCond)) {
    	return null;
   	}
    return author.name.like(nameCond);
}

 

return query .select .from .join 이 보이는가?

혁신적이지 아니할 수 없다는 것은 반박할 수 없지 않지 않다.

이렇게 JAVA 코드이며 직관적인 방식으로

동적쿼리를 생성하면 생기는 이점은 생각보다 엄청나다

  • 이클립스 / 인텔리제이 와 같은 컴파일러 문법 자동교정의 혜택을 받는다.
    스펠링 에러가 잡히니 컴파일하기 전에 오류를 발견할 수 있고,
    자동완성이 된다.
  • 코드를 재사용하기 쉽다. 자바코드니까!
  • JPQL 을 기반으로 하지만 JPQL보다 훨씬 가독성이 높다.

 

그렇다면 여기서 잠시 JPQL이 뭔지 알아보도록 하자.


JPQL 에 대한 간단한 고찰

JPQL은 JPA + SQL 의 조합이 어원... 인줄 알았으나,

JPQL(Java Persistence Query Language)의 줄인이며, 객체지향형 쿼리이다.

SQL문인데 이제 JPA 전용 SQL문으로 다시 탄생한 문법이다.

Result객체 = 엔티티객체 . JPA함수( " JPQL 문자열 " )

의 형태로 나타난다.

장점은 오라클이건 MySQL이건 설정 변경만 해주면 코드수정없이 DB이전이 된다.

특징은 복잡한 SQL작업을 위해 탄생한 놈이라, 각종 조인, 프로젝션, 페이징 등 거의 모든 기능이 존재한다.

간단한 Select Delete 같은 문법은 스프링 데이터 JPA* 사용을 추천한다.

(스프링 데이터 JPA의 관한 설명을 원한다면 아래 더보기 클릭)

더보기

스프링 데이터JPA에 대한 간단한 설명:

스프링 데이터 JPA는 간단한 select, delete 등 기능들을 전부 구현해놓은 라이브러리이다.
JPA를 활용하기 때문에 JPA에 대한 이해도가 필요하다.
물론 JPA에도 간단한 SQL 문 외에 수많은 기능들이 있지만,
한계점이 명확하기 때문에 잘 모르고 썼다가 추후에 코드를 갈아 엎는 경우도 많다고 하니,
잘 알아보고 쓰도록 하자.

간단하게 스프링 데이터 JPA 유무를 비교해보자면,

@Repository
@RequireArgsConstructor
public class MemberRepository {
    private final EntityManager;
    public List<Member> findByName(String name) {
        return em.createQuery("select m from Member m", Member.class)
                  .setParameter("name", name)
                  .getResultList();
    }
}

이 10줄의 코드를
public interface MemberRepository extends JpaRepository<Member, Long> {
    List<Member> findByName(String name);
}

이렇게 3줄로 끝낸다. 이미 JpaRepository 안에 findByName() 이 구현되어있기 때문.

 

 

아무튼 다시 JPQL로 돌아와서,

String jpql = "select m from Member as m where m.username = 'kim'";
List<Member> resultList = em.createQuery(jpql, Member.class).getResultList();

이게 JPQL 쿼리문으로 JPA를 사용한 간단한 예제이다.

언뜻보면 SQL과 별 차이 없어보이지만, 결정적인 차이점은

JPQL에 들어가는 모든 변수는 데이터베이스나 테이블이 아닌 객체이다.

jpql = "select m from Member as m where m.username = 'kim'"

m도 객체, from 절의 Member 도 객체 ! from 테이블 아니고 from 객체란 말임!

따라서 애석하게도 DB를 몰라야 더 배우기 쉽다고 유우-머를 칠 정도의 차이점을 가진다.

검색 자체를 엔티티 객체에서 하니까.

 

아무튼...

JPA, JPQL, QueryDSL 에 대해서 빠르게 알아봤다.

(다듬는중인 글입니다.)

 

참고 :
https://data-make.tistory.com/614 

https://ict-nroo.tistory.com/116

 

 

 

 

도움이 되셨다면 ♡공감 및 ↓광고클릭으로 응원해주세욥 :D

 

 

반응형