JPQL vs Querydsl

JIWOO YUN·2024년 3월 15일
0

Querydsl

목록 보기
1/7
post-custom-banner

JPQL vs Querydsl

JPQL 테스트

@SpringBootTest
@Transactional
public class QuerydslBasicTest {

    @Autowired
    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);
    }

    @Test
    public void startJPQL(){

        //member 1 찾기
        String qlString ="" +
                "select m from Member m " +
                "where m.username = :username ";

        Member findMember = em.createQuery(qlString, Member.class)
                .setParameter("username", "member1").getSingleResult();

        assertThat(findMember.getUsername()).isEqualTo("member1");
    }
  • EntityManager로 JPAQueryFactory 생성
  • JPQL : 문자(실행 시점에서 오류를 찾을 수있음.)
    • 파라미터를 직접 바인딩

QueryDsl 테스트

@SpringBootTest
@Transactional
public class QuerydslBasicTest {

    @Autowired
    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);
    }
    @Test
    public void startQuerydsl(){

        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 : JPQL 빌더
    • 컴파일 시점에서 오류를 찾을 수 있다. -> 자바 코드로 쿼리문을 짜기 때문에
    • 파라미터 바인딩 자동 처리

JPAQueryFactory를 필드로 제공하면 동시성 문제가 생기는가?

  • JPAQueryFactory 를 생성할 때 제공하는 EntityManager에 달려있다.
    • 여러 쓰레드에서 동시에 같은 EntityManager에 접근한다해도 트랜잭션이 별도의 영속성 컨텍스트를 제공하기 때문에 동시성 문제는 걱정하지 않아도 된다.
      • 트랜잭션이 중요.

querydsl에서 사용되는 fetch(), fetchone() 등등..

fetch() : 쿼리문을 처리하고 반환되는 값들을 그대로 리스트로 가져온다. -> 반환되는 데이터가 없을 경우 빈 리스트(empty list)가 반환됨.

fetchOne() : 단 하나의 데이터를 조회합니다. 쿼리문에 의해 반환되는 데이터가 0개면 NULL, 1개이면 정상, 2개 이상이면 NonUniqueResultException 발생.

fetchFirst() : limit(1).fetchOne() 과 동일.
  • 계속 마지막에 사용되길래 정확히 어떤걸 가지고 있는지 알고 싶어서 찾아봤었다.

Q타입 활용

  • querydsl 에서 엔티티로 설정된 클래스에서 Q 모델이라는 쿼리 타입 클래스를 미리 생성하고 메타 데이터로 사용아혀 쿼리를 메소드 기반으로 작성

사용방법 2가지

QMember qmember = new QMember("m"); //별칭 직접 사용하기
QMember qMember = QMember.member; //기본 인스턴스 사용하기.
    @Test
    public void startQuerydsl(){

        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");
    }
  • 위의 테스트에서 사용하듯이 사용.

기본 인스턴스 사용시 static import를 통해서 바로 Qmember가 만들어져있는것을 사용할 수있다.

import static study.querydsl.entity.QMember.*;
  • 추가시 밑의 검색 조건 쿼리처럼 member를 가져와서 사용가능.

검색 조건 쿼리

  • 검색조건은 .and(), .or()를 메서드 체인으로 연결할 수있음.
@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");

}
  • select 와 from을 selectFrom으로 합치는 것도 가능하다.
@Test
public void searchAndParam(){

    List<Member> result1 = queryFactory
            .selectFrom(member)
            .where(member.username.eq("member1"),
                    member.age.eq(10))
            .fetch();

    assertThat(result1.size()).isEqualTo(1);
}
  • where 문에 and를 쓰지 않아도 파라미터로 검색 조건을 추가시에 And 조건이 추가된다.

JPQL 이 제공하는 모든 검색 조건을 제공한다. -> Querydsl은 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%’ 검색
  • 주로 많이 사용하는 것들.

정렬

  • desc(),asc() : 일반 정렬
  • nullsLast(), nullsFirst() : null 데이터 순서 부여

집합

  • 마찬가지로 JPQL 이 제공하는 모든 집합 함수를 제공
JPQL
select
	count(m), 		//회원수
	sum(m.age),		//나이 합
	AVG(m.age),		//나이 평균
	MAX(m.age),		//최대 나이
	MIN(m.age)		//최소 나이
from Member m

Querydsl

    @Test
    public void aggregation() throws Exception{

        List<Tuple> result = queryFactory
                .select(member.count(),
                        member.age.sum(),
                        member.age.avg(),
                        member.age.max(),
                        member.age.min())
                .from(member)
                .fetch();

        Tuple tuple = result.get(0);

        assertThat(tuple.get(member.count())).isEqualTo(4);
        assertThat(tuple.get(member.age.sum())).isEqualTo(100);
        assertThat(tuple.get(member.age.avg())).isEqualTo(25);
        assertThat(tuple.get(member.age.max())).isEqualTo(40);
        assertThat(tuple.get(member.age.min())).isEqualTo(10);
    }

Tuple?

문서에 설명으로는 이렇게 나와있다.

Tuple defines an interface for generic query result projection

  • 쿼리 결과를 튜플 형태로 표현할 때 사용된다.

  • 여러 타입을 조회할 때 사용하기 위해서 querydsl에서 만든 것

profile
열심히하자
post-custom-banner

0개의 댓글