이 수업에서는 데이터 생성, 조회가 중요한 게 아니라서, 모든 테스트 전에 아래의 함수를 실행해서 데이터를 생성한다!
@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);
}
}
member1이라는 이름을 가진 Member를 찾아라!
@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");
}

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 : 문자 (실행하고 나서 오류 발생, 런타임시 오류 발생)
Querydsl : 코드 (코드 작성시 오류 발생, 컴파일 시점에 오류 발생)
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"))