2 분 소요


예제 도메인 모델

1

(코드는 생략..)


기본 문법

시작 - JPQL vs Querydsl

테스트 기본 코드

@SpringBootTest
@Transactional
public class QuerydslBasicTest {

    @PersistenceContext EntityManager em;

    @BeforeEach
    public void before() {
        Team teamA = new Team("teamA");
        Team teamB = new Team("teamB");
        em.persist(teamA);
        em.persist(teamB);

        Member member1 = new Member("member1", 10, teamA);
        Member member2 = new Member("member2", 20, teamA);
        Member member3 = new Member("member3", 30, teamB);
        Member member4 = new Member("member4", 40, teamB);
        
        em.persist(member1);
        em.persist(member2);
        em.persist(member3);
        em.persist(member4);
    }
}

Querydsl vs JPQL

@Test
void startJPQL() {
    // member1 찾기
    Member findMember = em.createQuery(
                "select m from Member m" +
                " where m.username = :username")
                .setParameter("username", "member1")
                .getSingleResult();
}

@Test
void startQuerydsl() {
    // member1 찾기
    JPAQueryFactory queryFactory = new JpaQueryFactory(em);
    QMember m = new QMember("m");

    Member findMember = queryFactory
            .select(m)
            .from(m)
            .where(m.username.eq("member1")) // 파라미터 바인딩 처리
            .fetchOne();
}
  • EntityManagerJPAQueryFactory생성
  • Querydsl은 JPQL 빌더
  • JPQL : 문자(실행 시점 오류), Querydsl : 코드(컴파일 시점 오류)
  • JPQL : 파라미터 바인딩 직접, Querydsl : 파라미터 바인딩 자동 처리

JPAQueryFactory를 필드로

@SpringBootTest
@Transactional
public class QuerydslBasicTest {

    @PersistenceContext EntityManager em;
    
    JPAQueryFactory queryFactory;

    @BeforeEach
    public void before() {

        queryFactory = new JPAQueryFactory(em);
        
        // ...
    }
}

JPAQueryFactory를 필드로 제공하면 동시성 문제는..?
동시성 문제는 JPAQueryFactory를 생성할 때 제공하는 EntityManager(em)에 달려있다. 스프링 프레임워크는 여러 쓰레드에서 동시에 같은 EntityManager에 접근해도, 트랜잭션 마다 별도의 영속성 컨텍스트를 제공하기 때문에, 동시성 문제는 걱정하지 않아도 된다.

기본 Q-Type 활용

Q클래스 인스턴스를 사용하는 2가지 방법

QMember qMember = new QMember("m"); // 별칭 직접 지정
QMember qMember = Qmember.member; // 기본 인스턴스 사용

기본 인스턴스를 static import와 함께 사용

import static study.querydsl.entity.QMember.*;

@Test
void startQuerydsl() {
    // member1 찾기
    Member findMember = queryFactory
            .select(member)
            .from(member)
            .where(member.username.eq("member1"))
            .fetchOne();
}

[참고] : 같은 테이블을 조인해야 하는 경우가 아니면 기본 인스턴스를 사용.

검색 조건 쿼리

기본 검색 쿼리

@Test
void search() {
    Member findMember = queryFactory
            .selectFrom(member)
            .where(member.username.eq("member1")
                    .and(member.age.eq(10)))
            .fetchOne();
}
  • 검색 조건은 .and(), .or()를 메서드 체인으로 연결할 수 있다.

[참고] : select, fromselectFrom으로 합칠 수 있다.

JPQL이 제공하는 모든 검색 조건 제공

member.username.eq("member1") // username = 'member1'
member.username.ne("member1") //username != 'member1'
member.username.eq("member1").not() // username != 'member1'

member.username.isNotNull() //이름이 is not null

member.age.in(10, 20) // age in (10,20)
member.age.notIn(10, 20) // age not in (10, 20)
member.age.between(10,30) //between 10, 30

member.age.goe(30) // age >= 30
member.age.gt(30) // age > 30
member.age.loe(30) // age <= 30
member.age.lt(30) // age < 30

member.username.like("member%") //like 검색
member.username.contains("member") // like ‘%member%’ 검색
member.username.startsWith("member") //like ‘member%’ 검색
...

AND 조건을 파라미터로 처리

@Test
void searchAndParam() {
    List<Member> result = queryFactory
            .selectFrom(member)
            .where(member.username.eq("member1"), member.age.eq(10))
            .fetch();
}
  • where()에 파라미터로 검색조건을 추가하면 AND조건이 추가됨
  • 이 경우 null값은 무시 -> 메서드 추출을 활용해서 동적 쿼리를 깔끔하게 만들 수 있다.


<출처 : 인프런 - 실전! Querydsl(김영한)>

댓글남기기