Querydsl 동적 페이지네이션 쿼리
Spring에서 Querydsl로 동적 커서 기반 페이지네이션 쿼리를 구성하는 방법에 대해 알아보겠습니다.
개요
동적 쿼리란?
동적 쿼리는 상황에 알맞는 쿼리문을 생성해서 데이터베이스에 날려주는것 입니다.
예시 1
users
테이블에서 커서 기반 페이지네이션으로 회원을 조회하고 싶으면 다음과 같이 코드를 구현해야 됩니다.
JpaRepository
1
2
3
public interface UsersRepository extends JpaRepository<Long, Users> {
Page<Users> findAll(Pageable pageable);
}
Querydsl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
@RequiredArgsConstructor
public class UserRepositoryImpl implements UserCustomRepository {
private final JPAQueryFactory queryFactory;
@Override
public Page<Users> findByPage(long pageFrom, int pageSize) {
Long count = queryFactory.select(user.count())
.from(user)
.where(
user.isSeekingTeam.isTrue()
).fetchOne();
Pageable pageable = Pageable.ofSize(pageSize);
if (count == null || count == 0)
return new PageImpl<>(List.of(), pageable, 0);
List<User> users = queryFactory.selectFrom(user)
.where(
user.id.lt(pageFrom),
user.isSeekingTeam.isTrue()
).orderBy(user.createdAt.desc())
.limit(pageSize)
.fetch();
return new PageImpl<>(users, pageable, count);
}
}
SQL
1
SELECT * FROM users WHERE user_id<100 ORDER BY created_at DESC LIMIT 10;
예시 2
동일한 조건에서 position
이 BACKEND
인 회원으로 조건을 추가하고 싶으면 다음과 같이 코드를 구현해야 됩니다.
JpaRepository
1
2
3
public interface UsersRepository extends JpaRepository<Long, Users> {
Page<Users> findAllByPosition(Pageable pageable, Position position);
}
Querydsl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
@RequiredArgsConstructor
public class UserRepositoryImpl implements UserCustomRepository {
private final JPAQueryFactory queryFactory;
@Override
public Page<Users> findByPage(Position position, long pageFrom, int pageSize) {
Long count = queryFactory.select(user.count())
.from(user)
.where(
user.position.eq(position)
).fetchOne();
Pageable pageable = Pageable.ofSize(pageSize);
if (count == null || count == 0)
return new PageImpl<>(List.of(), pageable, 0);
List<User> users = queryFactory.selectFrom(user)
.where(
user.id.lt(pageFrom),
user.position.eq(position)
).orderBy(user.createdAt.desc())
.limit(pageSize)
.fetch();
return new PageImpl<>(users, pageable, count);
}
}
SQL
1
SELECT * FROM users WHERE user_id<100 AND position='BACKEND' ORDER BY created_at DESC LIMIT 10;
동적 쿼리 구현
예시1도 필요하고 예시2도 필요한 쿼리라고 가정을 하겠습니다. 정적 쿼리만 활용한다면 예시1과 예시2의 코드를 둘 다 작성해야 됩니다.
하지만 동적 쿼리를 사용하면 두개의 코드를 하나로 묶어서 효율적이고 간결하게 코드를 구성할 수 있습니다.
동적 쿼리를 활용하기 위해서는 Jpa
, Jdbc
또는 Querydsl
등을 활용할 수 있는데, JpaRepository interface로는 활용할 수 없습니다. 이 중 컴파일 과정에서 에러를 발견할 수 있는 Querydsl로 동적 쿼리를 작성해 보겠습니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
@RequiredArgsConstructor
public class UserRepositoryImpl implements UserCustomRepository {
private final JPAQueryFactory queryFactory;
@Override
public Page<User> findPage(Position position, long pageFrom, int pageSize) {
Long count = queryFactory.select(user.count())
.from(user)
.where(
positionEq(position),
).fetchOne();
Pageable pageable = Pageable.ofSize(pageSize);
if (count == null || count == 0)
return new PageImpl<>(List.of(), pageable, 0);
List<User> users = queryFactory.selectFrom(user)
.where(
user.id.lt(pageFrom),
positionEq(position),
).orderBy(user.createdAt.desc())
.limit(pageSize)
.fetch();
return new PageImpl<>(users, pageable, count);
}
private Predicate positionEq(Position position) {
return position != Position.NONE ? user.position.eq(position) : null;
}
}
위의 코드를 보면 positionEq()
메서드에서 만약 Position.NONE
일 경우에 where문에 null
을 반환하고, 반대의 경우에는 user.position.eq(position)
을 반환하게 되어있습니다. Querydsl은 where문에 null이 들어오면 무시를 하고 쿼리문을 구성할 수 있기에 가능한 것입니다.
이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.