(스프링프레임워크학원)Querydsl의 종류_JPA 및 Spring Data JPA에서 Querydsl 사용하는 방법의 종류

FSP 0 304 02.01 16:02

 

(스프링프레임워크학원)Querydsl의 종류_JPA 및 Spring Data JPA에서 Querydsl 사용하는 방법의 종류

 

www.topcredu.co.kr

 

Querydsl은 엔티티로 설정된 모델 클래스와 동일한 패키지에 "Q" 모델이라는 쿼리타입 클래스를 미리 생성해 놓고 메타데이터로 사용하여 쿼리를 메소드 기반으로 작성합니다. Querydsl을 사용하면 보다 쉽고 직관적으로 처리할 수 있습니다.

 

3.2.1. Querydsl 구분

 

Thread Safe

as Bean(Singleton)

Use EntityManager

(First Caching)

Use Entity Class

JPAQuery

new

v

v

JPAQueryFactory

v

v

v

JPASQLQuery

new

v (No First Caching)

Table

SQLQuery

new

DataSource

Table

SQLQueryFactory

v

DataSource

Table

 

n     쿼리문을 작성하기 위해서 모두 Q 타입 클래스를 사용합니다.

n     JPAQuery, JPAQueryFactory 클래스를 사용하면 EntityManager를 통해서 질의가 처리되고 이 때 사용하는 쿼리문은 JPQL 입니다.

n     SQLQuery, SQLQueryFactory 클래스를 사용하면 JDBC 기술을 사용하여 질의가 처리되고 이 때 사용하는 쿼리문은 SQL입니다.

n     JPASQLQuery 클래스를 사용하면 EntityManager를 통해서 질의가 처리되고 이 때 사용하는 쿼리문은 SQL입니다. 추가적으로 EntityManager를 이용하고 싶을 때 사용합니다.


3.2.2. 엔티티 클래스를 만들어서 사용

"Q" 모델은 클래스 내 자체적으로 이미 인스턴스를 static 변수로 가지고 있기 때문에 예를 들어 "QEmp.emp" 처럼 간단하게 사용할 수 있습니다.

 

1. JPAQuery

QEmp emp = QEmp.emp;

JPAQuery query = new JPAQuery(em);     

query.select(emp).from(emp).where(emp.ename.eq("SMITH"));     

List<Emp> result = query.fetch();

 

JPAQuery 생성자에 EntityManager 객체를 전달합니다.

select 메소드는 얻고자 하는 칼럼들을 지정하는 Projection설정용입니다.

from 메소드는 쿼리대상을 지정합니다.

where 메소드는 쿼리 조건을 적용하는 필터입니다.

fetch 메소드로 복수의 로우 데이터를 얻을 수 있습니다.

 

대부분의 데이터베이스는 저장하는 정보를 필터링할 때 대소문자를 구분하기 때문에 "SMITH" 문자열을 소문자로 사용하면 해당 데이터가 없다고 할 것이니 주의가 필요합니다.

 

2. JPAQueryFactory

JPAQueryFactory  queryFactory = new JPAQueryFactory(em);

List<Emp> emps = queryFactory.selectFrom(emp).where(emp.ename.eq("SMITH")).fetch();

 

JPAQueryFactory JPAQuery를 만들어서 사용하는 방식입니다. JPAQueryFactory를 빈 컨테이너에 등록해 놓고 DI 받아 사용하면 편리합니다. JPAQueryFactory JPQLQueryFactory 인터페이스를 구현했으며 JPAQuery 인스턴스를 포함하여 다양한 방법으로 쿼리 할 수 있습니다. 생성할 때 EntityManager만 인자로 넣어 생성할 수도 있고 JPQLTemplate도 같이 인자로 줘서 생성 할 수 있습니다. 다이나믹하게 데이터베이스가 바뀌는 경우는 거의 없기 때문에 보통 JPQLTemplate은 생략하고 사용합니다.

 

selectFrom(emp) 메소드는 select(emp).from(emp) 선언의 축약형태입니다.

eq 메소드는 "=" 연산자를 대체하는 메소드입니다.

 

3.2.3. 엔티티 클래스를 만들지 않고 사용

 

1. JPASQLQuery

엔티티 클래스를 만들지 않고 사용할 수 있습니다. 엔티티 클래스를 작성한 후 이를 바탕으로 테이블을 구성하여 진행하는 개발방식 대신 이미 테이블이 존재하는 경우 이를 바탕으로 쿼리타입을 생성하여 질의할 때 이용하는 방식입니다.

 

이는 엔티티매니저의 createNativeQuery 메소드를 사용하는 것과 결과가 같습니다. 하지만 둘 사이에는 큰 차이가 존재합니다.

 

JPASQLQuery 클래스를 사용하거나 em.createNativeQuery 메소드를 사용하거나 둘 다 개발자가 지정해서 알려 준 쿼리를 사용합니다. em.createNativeQuery에서 파라미터로 넘겨주는 모델클래스는 엔티티이므로 여러 엔티티 클래스의 연관관계에 따른 EAGER 로딩정책을 지키기 위해서 추가적으로 쿼리가 더 수행될 수 있습니다.

하지만 new JPASQLQuery<Void>(em, templates) 코드에서 보는 것처럼 엔티티매니저를 사용한다고 하더라도 엔티티 클래스를 알려 준 것은 아니므로 연관관계에 따른 추가적인 쿼리가 수행되지 않는다는 차이점이 존재합니다. 더불어 엔티티 클래스를 이용한 것이 아니므로 1차 캐싱기능을 이용하지 못합니다. 질의를 하면 엔티티매니저가 매번 데이터베이스에 질의하여 데이터를 얻어다 줄 것입니다.

 

JPAQuery 객체로는 인라인뷰 쿼리를 작성하지 못합니다. 따라서 인라인뷰를 사용하고자 하는 경우에는 대신 JPASQLQuery를 사용해야 합니다. 인라인뷰를 사용하지 못하는 것은 Querydsl의 한계가 아니라 JPA의 기술적인 한계입니다.

 

JPASQLQuery를 사용하기 위해서 우선 테이블을 바탕으로 리버스 엔지니어링을 진행하여 쿼리타입 클래스를 생성해야 합니다. 이 때 필요하다면 모델 클래스를 같이 생성할 수 있습니다. 메이븐 설정에 querydsl-maven-plugin을 추가하여 Q 타입 클래스를 생성한 다음 이용합니다.

 

SQLTemplates templates = new DerbyTemplates();

QEmp emp = new QEmp("emp");

JPASQLQuery<?> query = new JPASQLQuery<Void>(em, templates);

List<Tuple> rows = query.select(emp.empno, emp.ename).from(emp)

     .where(emp.ename.eq("SMITH").fetch();

 

SQLTemplates의 구현체는 데이터베이스에 따라서 선택해서 사용합니다. 선택된 구현체를 파라미터로 전달하고 사용해야 하는 Dialect를 판단하는 용도로 사용됩니다.

2. SQLQuery

SQLQuery를 직접 사용하는 방법보다는 SQLQueryFactory를 통해서 사용하는 방법을 권장합니다. 따라서 SQLQueryFactory를 사용하는 방법을 바로 살펴 보겠습니다.

 

3. SQLQueryFactory

SQLTemplates templates = new MySQLTemplates();

Configuration configuration = new Configuration(templates);

SQLQueryFactory queryFactory = new SQLQueryFactory(configuration, dataSource);

QEmp emp = new QEmp("emp");

List<Emp> result  = queryFactory.selectFrom(emp).where(emp.ename.eq("SMITH")).fetch();          

 

SQLQueryFactory 생성자에 설정정보인 Configuration 과 데이터베이스 연결정보인 DataSource를 주고 있습니다. 따라서 엔티티매니저를 거쳐서 사용하는 것이 아닌 개발자가 직접 데이터베이스가 이해하는 SQL을 작성한 다음 JDBC 기술을 사용하여 처리하는 방식이라는 것을 알 수 있습니다.

 

다음은 이해를 돕기위한 com.querydsl.sql.AbstractSQLQuery.fetch 메소드 소스의 일부분 입니다.

//… 생략
final PreparedStatement stmt = getPreparedStatement(queryString);

try {

     setParameters(stmt, constants,

          serializer.getConstantPaths(), queryMixin.getMetadata().getParams());

     context.addPreparedStatement(stmt);

     listeners.prepared(context);

 

     listeners.preExecute(context);

     final ResultSet rs = stmt.executeQuery();

     listeners.executed(context);

     //... 생략

} finally {

     stmt.close();

}

//... 생략

 

SQLQueryFactory를 이용하는 경우 내부적으로 Querydsl JDBC기술을 사용한다는 것을 알 수 있습니다.

  

, , , , , , , , , , , , , , , , , ,

Comments