Programming/Querydsl

Querydsl - 기본 문법 (1) (기본 Q 타입, 검색, AND)

잇(IT) 2023. 7. 26. 23:52

- JPQL vs Querydsl

@SpringBootTest
@Transactional
public class QuerydslBasicTest {

    @Autowired
    EntityManager em;

    JPAQueryFactory queryFactory;

    @BeforeEach
    public void before() {
        queryFactory = new JPAQueryFactory(em);
        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);
    }

    @Test
    public void startJPQL() {
        //member1을 찾아라
        String qlString = "select m from Member m " +
                "where username = :username";
        Member findMember = em.createQuery(qlString, Member.class)
                .setParameter("username", "member1")
                .getSingleResult();

        assertThat(findMember.getUsername()).isEqualTo("member1");
    }

    @Test
    public void startQuerydsl() {
//        JPAQueryFactory queryFactory = new JPAQueryFactory(em); 얘는 필드로 가져갈 수 있다.

//        QMember m = new QMember("m"); // 첫번째
//        QMember m = QMember.member; // 두번째

//        Member findMember = queryFactory
//                .select(m)
//                .from(m)
//                .where(m.username.eq("member1")) //파라미터 바인딩 처리
//                .fetchOne();

                Member findMember = queryFactory
                .select(member)
                .from(member)
                .where(member.username.eq("member1")) //파라미터 바인딩 처리
                .fetchOne();

        assertThat(findMember.getUsername()).isEqualTo("member1");
    }

    @Test
    public void search() {
        Member findMember = queryFactory
                .selectFrom(member)
                .where(member.username.eq("member1")
                        .and(member.age.eq(10)))
                .fetchOne();

        assertThat(findMember.getUsername()).isEqualTo("member1");
        assertThat(findMember.getAge()).isEqualTo(10);
    }

    @Test
    public void searchAndParam() { // ,로 이어나가면 전부 and로 연결된다.
        Member findMember = queryFactory
                .selectFrom(member)
                .where(
                        member.username.eq("member1"),
                        (member.age.eq(10)))
                .fetchOne();

        assertThat(findMember.getUsername()).isEqualTo("member1");
        assertThat(findMember.getAge()).isEqualTo(10);
    }
}

@SpringBootTest
@Transactional
public class QuerydslBasicTest {

    @Autowired
    EntityManager em;

    JPAQueryFactory queryFactory;

    @BeforeEach
    public void before() {
        queryFactory = new JPAQueryFactory(em);
        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은 JPQL을 빌드하는 역활을 하기 떄문에 EntityManager를 통해 실행된다.

- Querydsl을 사용하기 위해선 JPAQueryFactory객체를 사용해야 하고, EntityManager를 파라미터로 넣어준다.

- @BeforeEach를 통해 테스트 메서드가 실행되기 이전에 공통으로 mamber 엔티티를 생성한다.

 


- JPQL Test 코드

@Test
    public void startJPQL() {
        //member1을 찾아라
        String qlString = "select m from Member m " +
                "where username = :username";
        Member findMember = em.createQuery(qlString, Member.class)
                .setParameter("username", "member1")
                .getSingleResult();

        assertThat(findMember.getUsername()).isEqualTo("member1");
    }

- em.createQuery를 통해 JPQL를 사용하여 동적 쿼리를 작성하는 방법이다.

- 파라미터 바인딩 방식으로 username에 member1에 해당하는 엔티티를 찾아오는 쿼리이다.


- Querydsl

- Querydsl

@Test
public 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();
        
 assertThat(findMember.getUsername()).isEqualTo("member1");
}

- 가장 기본적인 Querydsl을 사용한 방식이다.

- JPAQueryFactory에 EntityManager를 파라미터로 넘겨 객체를 생성한다.

- new QMember를 통해 Querydsl을 통해 생성된 QMember 클래스를 생성한다. 

new QMember("m");

("m")

- "m"은 별칭으로 사용되는데 잘 사용하지 않는다.

- JPAQueryFactory 객체를 통해 SQL과 유사한 형태로 쿼리를 작성해주면 된다.

 

JPAQueryFactory 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
public void startQuerydsl3() {
 	//member1을 찾아라.
    
    // QMember m = QMember.member;를 static import를 통해 생략한다.
    // 기존에 static import를 하지 않으면 .select(QMember.member)와 같이 작성해줘야 한다.
    
 	Member findMember = queryFactory
 		.select(member)
 		.from(member)
 		.where(member.username.eq("member1"))
 		.fetchOne();
        
 assertThat(findMember.getUsername()).isEqualTo("member1");
}

- static import를 통해 member 엔티티명이 드러날 수 있도록 코드를 작성해주는 것이 좋다.


- 검색 조건 쿼리

 

- 기본 검색 쿼리

@Test
    public void search() {
        Member findMember = queryFactory
                .selectFrom(member)
                .where(member.username.eq("member1")
                        .and(member.age.eq(10)))
                .fetchOne();

        assertThat(findMember.getUsername()).isEqualTo("member1");
        assertThat(findMember.getAge()).isEqualTo(10);
    }

- 검색 조건은 , and() , or()를 메서드 체인으로 연결할 수 있다.

 

* selectFrom은 select, From을 합친것이다.


- 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%’ 검색
...

- JPQL은 위와 같은 많은 메서드를 제공한다.


- AND 조건을 파라미터로 처리

@Test
    public void searchAndParam() { // ,로 이어나가면 전부 and로 연결된다.
        Member findMember = queryFactory
                .selectFrom(member)
                .where(
                        member.username.eq("member1"),
                        (member.age.eq(10)))
                .fetchOne();

        assertThat(findMember.getUsername()).isEqualTo("member1");
        assertThat(findMember.getAge()).isEqualTo(10);
    }

-where()에 파라미터로 검색조건을 추가하면 AND 조건이 추가된다.

- .and를 통해 and 조건을 추가할 수 있지만 

 member.username.eq("member1"),
(member.age.eq(10)))

- 코드와 같이 ,를 사용하면 Querydsl이 알아서 and로 처리한다.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

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

728x90