@SpringBootTest
@Transactional
public class QuerydslBasicTest {
@Test
void search() {
Member findMember = queryFactory
.selectFrom(member)
.where(member.username.eq("member1")
.and(member.age.eq(10))
).fetchOne();
assertThat(findMember.getUsername()).isEqualTo("member1");
}
}
and
, or
은 메서드 체인으로 합칠 수 있다.
Member findMember = queryFactory
.selectFrom(member)
.where(member.username.eq("member1")
,(member.age.eq(10))
).fetchOne();
and
를 이용하지말고 ,
로 대체 가능
(마크다운 표 만들기 어렵군요...)
코드 | 분석 |
---|---|
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%’ 검색 |
fetch()
: 리스트 조회, 데이터 없으면 빈 리스트 반환
fetchOne()
: 단 건 조회
fetchFirst()
: limit(1).fetchOne()
fetchResults()
: 페이징 정보 포함, total count 쿼리 추가 실행
fetchCount()
: count 쿼리로 변경해서 count 수 조회
@SpringBootTest
@Transactional
public class QuerydslBasicTest {
@Test
void result() {
// List
List<Member> fetch = queryFactory
.selectFrom(member)
.fetch();
// 단건
Member findMember1 = queryFactory
.selectFrom(member)
.fetchOne();
// 맨 처음 한 건만 조회
Member findMember2 = queryFactory
.selectFrom(member)
.fetchFirst();
// 페이징에서 사용
QueryResults<Member> results = queryFactory
.selectFrom(member)
.fetchResults();
// count 쿼리로 변경
long count = queryFactory
.selectFrom(member)
.fetchCount();
}
}
orderBy
메소드를 이용해 정렬을 한다.
@SpringBootTest
@Transactional
public class QuerydslBasicTest {
/**
*회원 정렬 순서
* 1. 회원 나이 내림차순(desc)
* 2. 회원 이름 올림차순(asc)
* 단 2에서 회원 이름이 없으면 마지막에 출력(nulls last)
* */
@Test
public void sort() {
em.persist(new Member(null, 100));
em.persist(new Member("member5", 100));
em.persist(new Member("member6", 100));
List<Member> result = queryFactory
.selectFrom(member)
.where(member.age.eq(100))
// 정렬
.orderBy(member.age.desc(), member.username.asc().nullsLast())
.fetch();
Member member5 = result.get(0);
Member member6 = result.get(1);
Member memberNull = result.get(2);
assertThat(member5.getUsername()).isEqualTo("member5");
assertThat(member6.getUsername()).isEqualTo("member6");
assertThat(memberNull.getUsername()).isNull();
}
}
asc()
: 오름차순
desc()
: 내림차순
nullsFirst()
: null을 정렬 결과의 처음으로
nullsLast()
: null을 정렬 결과의 마지막으로
limit
, offset
파라미터를 통해 페이징을 할 수 있다.fetch()
는 결과의 리스트를 조회한다.
이 때는 결과만 조회하기에 select
쿼리만 나간다.
@SpringBootTest
@Transactional
public class QuerydslBasicTest {
@Test
public void paging1() {
List<Member> result = queryFactory
.selectFrom(member)
.orderBy(member.username.desc())
// 0부터 시작(zero index)
.offset(1)
// 최대 2건 조회
.limit(2)
.fetch();
assertThat(result.size()).isEqualTo(2);
}
}
select
m1_0.member_id,
m1_0.age,
m1_0.team_id,
m1_0.username
from
member m1_0
order by
m1_0.username desc
offset
? rows
fetch
first ? rows only
fetchResults
는 페이징에 관련된 정보들을 함께 가져온다.
@SpringBootTest
@Transactional
public class QuerydslBasicTest {
@Test
public void paging2() {
QueryResults<Member> queryResults = queryFactory
.selectFrom(member)
.orderBy(member.username.desc())
.offset(1)
.limit(2)
.fetchResults();
assertThat(queryResults.getTotal()).isEqualTo(4);
assertThat(queryResults.getLimit()).isEqualTo(2);
assertThat(queryResults.getOffset()).isEqualTo(1);
assertThat(queryResults.getResults().size()).isEqualTo(2);
}
}
참고 :
페이징 쿼리를 작성할 때, 데이터를 조회하는 쿼리는 여러 테이블을 조인해야 하지만, count 쿼리
는 조인이 필요 없는 경우도 있다.
자동화된 count 쿼리는 원본 쿼리와 같이 모두 조인을 해버리기 때문에 성능이 안나올 수 있다.
count 쿼리에 조인이 필요없는 성능 최적화가 필요하다면, count 전용 쿼리를 별도로 작성해야 한다.
count()
, sum()
, avg()
, max()
, min()
사용가능
이 때, 반환 타입은 Tuple
을 이용한다.
@SpringBootTest
@Transactional
public class QuerydslBasicTest {
@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);
}
}
Member
엔티티를 team.name
으로 group해서 이 때 team.name
과 member.age.avg()
를 선택하고 싶다.
@SpringBootTest
@Transactional
public class QuerydslBasicTest {
@Test
public void group() throws Exception {
List<Tuple> result = queryFactory
.select(team.name, member.age.avg())
.from(member)
.join(member.team, team)
.groupBy(team.name)
.fetch();
Tuple teamA = result.get(0);
Tuple teamB = result.get(1);
assertThat(teamA.get(team.name)).isEqualTo("teamA");
assertThat(teamA.get(member.age.avg())).isEqualTo(15);
assertThat(teamB.get(team.name)).isEqualTo("teamB");
assertThat(teamB.get(member.age.avg())).isEqualTo(35);
}
}
GroupBy
가 있으면 당연히 Having
절도 사용 가능해야겠죠
아래와 같이 group한 속성에 대한 조건을 달아주면 됩니다.
@SpringBootTest
@Transactional
public class QuerydslBasicTest {
@Test
public void groupHaving() throws Exception {
List<Tuple> result = queryFactory
.select(team.name, member.age.avg())
.from(member)
.join(member.team, team)
.groupBy(team.name)
.having(team.name.eq("teamA"))
.fetch();
Tuple teamA = result.get(0);
assertThat(teamA.get(team.name)).isEqualTo("teamA");
assertThat(teamA.get(member.age.avg())).isEqualTo(15);
}
}
참고 :