7. JPQL vs Querydsl

민정·2023년 1월 5일

QueryDSL

목록 보기
7/18
post-thumbnail

📌 시작에 앞서...

이 수업에서는 데이터 생성, 조회가 중요한 게 아니라서, 모든 테스트 전에 아래의 함수를 실행해서 데이터를 생성한다!

@BeforeEach 어노테이션을 사용해서 각 테스트 전에 해당 함수가 실행되도록했다!

@SpringBootTest
@Transactional
public class QuerydslBasicTest {

    @Autowired
    EntityManager em;

    @BeforeEach // 모든 테스트 전에 실행됨
    public void before() {
        // given
        // 팀 2개 생성, 저장
        Team teamA = new Team("teamA");
        Team teamB = new Team("teamB");

        em.persist(teamA);
        em.persist(teamB);

        // 멤버 4명 생성, 저장
        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);
    }
}


🤩 JPQL, Querydsl 작성하기

member1이라는 이름을 가진 Member를 찾아라!

1. JPQL

@Test
    public void startJPQL() {
        // memeber1을 찾아라
        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");
    }



2. Querydsl

EntityManager를 사용해서 JPAQueryFactory 생성

Querydsl은 JPQL 빌더

먼저 Q파일을 생성해야한다.

📌 Q 파일 생성

gradle 탭 - Tasks - other - compileQuerydsl 실행

build/generated 안에 생성된 Q파일 확인 가능

@Test
    public void startQuerydsl() {
        // memeber1을 찾아라

        // 1. 일단 JPAQueryFactory 생성으로 시작
        JPAQueryFactory queryFactory = new JPAQueryFactory(em); // em 넘겨줘야함

        // 2. Q클래스 생성
        // QMember, QTeam 파일 생성: gradle 탭 - Tasks - other - compileQuerydsl 실행
        // >> build/generated 안에 생성된 Q파일 확인 가능
        QMember m = new QMember("m");// "m"이라는 값으로 어떤 QMember인지 구분

        // 3. 쿼리 작성
        Member findMember = queryFactory
                .select(m)
                .from(m)
                .where(m.username.eq("member1")) // 중요!) 파라미터 바인딩 대신 eq로 짜도 자동으로 JDBC에 있는 prepareStatement로 파라미터 바인딩함. -> 쿼리 나간 거 보면 ?가 있음.
                                                        // ** 파라미터 바인딩 -> SQL Injection 공격 방지 가능
                .fetchOne();

        // 검증
        assertThat(findMember.getUsername()).isEqualTo("member1");
    }

📌 참고

JPAQueryFactory는 필드 레벨로 가져와도 된다. (권장)

필드에 선언하고 생성은 각 함수내에서해도 된다.

	@SpringBootTest
	@Transactional
	public class QuerydslBasicTest {

    	@Autowired
    	EntityManager em;

    	JPAQueryFactory queryFactory; // 필드 레벨로 가져와도 됨. 동시성 문제 고려 안해도 됨.
    	...
    
    	@Test
    	public void startQuerydsl() {
    
        // 1. 일단 JPAQueryFactory 생성으로 시작
        queryFactory = new JPAQueryFactory(em); // em 넘겨줘야함
        
        ...
    	}
	}

📌 동시성 문제

Q: JPAQueryFactory를 필드로 제공하면 동시성 문제는 없나?

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



🧐 비교 : JPQL vs Querydsl

1. 쿼리문 잘못 작성시 오류 알려주는 시점

JPQL : 문자 (실행하고 나서 오류 발생, 런타임시 오류 발생)

Querydsl : 코드 (코드 작성시 오류 발생, 컴파일 시점에 오류 발생)

2. 파라미터 바인딩

JPQL : 파라미터 바인딩 직접

em.createQuery("select m from Member m where m.username = :username")
	.setParameter("username", "member1")

Querydsl : 파라미터 바인딩 자동 처리

queryFactory
	.select(m)
	.from(m)
	.where(m.username.eq("member1"))


출처

김영한 강사님 - 인프런 실전! Querydsl

0개의 댓글