๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ
์นดํ…Œ๊ณ ๋ฆฌ ์—†์Œ

[Daily Retrospect] Ep19. DB ์Šคํ„ฐ๋”” ์‹œ์ž‘ ๋ฐ Querydsl ๊ณต๋ถ€

by Bhinney 2023. 1. 11.

๐Ÿ—“ DATE : 2023.01.10 TUE


DB ์Šคํ„ฐ๋”” ์‹œ์ž‘ ๋ฐ Querydsl ๊ณต๋ถ€

 

์˜ค๋Š˜๋ถ€ํ„ฐ ๋ฐ์ดํ„ฐ ๋ฒ ์ด์Šค ์Šคํ„ฐ๋””๋ฅผ ์‹œ์ž‘ํ–ˆ๋‹ค.

 

์•„์ง์€ ์ฒ˜์Œ์ด๋ผ ๊ทœ์น™์ด๋‚˜ ๋ฐฉํ–ฅ์„ฑ์— ๋Œ€ํ•œ ์–˜๊ธฐ๋ฅผ ๋งŽ์ด ๋‚˜๋ˆ„์—ˆ๋‹ค.

 

์–ด๋–ค ๋””๋น„๋ฅผ ๋จผ์ € ๊ณต๋ถ€ํ•  ์ง€, ์–ด๋–ป๊ฒŒ ๊ณต๋ถ€ํ•  ์ง€์— ๋Œ€ํ•ด์„œ ์ด์•ผ๊ธฐ๋ฅผ ํ•˜์˜€๋‹ค.

 

ํ•ด๋‹น ์ด์•ผ๊ธฐ ์ „์— ๋ฏธ๋ฆฌ ํ’€์–ด๋ณด๊ธฐ๋กœ ํ•œ ๋ฌธ์ œ๋“ค์„ ํ’€์–ด๋ณด์•˜๋‹ค.

 

๊ทธ ๊ณผ์ •์—์„œ WHERE๊ณผ HAVING์— ๋Œ€ํ•ด ์ด์•ผ๊ธฐ๋ฅผ ๋‚˜๋ˆ„์—ˆ๋‹ค.

 

์ด ๋ถ€๋ถ„์€ ๋‚ด๊ฐ€ ๋‹ค์‹œ ๊ณต๋ถ€ํ•ด์„œ ์ •๋ฆฌํ•ด์„œ ๋ธ”๋กœ๊น…์„ ํ•˜๋Š” ๊ฒƒ์ด ์ข‹์„ ๊ฒƒ ๊ฐ™์•˜๋‹ค.

 

 

๊ทธ๋ฆฌ๊ณ  ์–ด์ œ์— ์ด์–ด Querydsl์„ ๊ณต๋ถ€ํ•˜๊ณ  ์‚ฌ์šฉํ•ด๋ณด๊ณ  ์žˆ๋‹ค.

 

์ด์ œ MutliResponseDto๋ฅผ ๋งŒ๋“ค์–ด ํŽ˜์ด์ง€ ์ •๋ณด๊นŒ์ง€ ๋„˜๊ฒจ๋ณด๊ณ  ์žˆ์—ˆ๋‹ค.

 

๊ทผ๋ฐ ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ–ˆ๋‹ค.

์•„๋ž˜์˜ ์‚ฌ์ง„์ฒ˜๋Ÿผ page ์ •๋ณด์™€ totalElements, totalPages๊ฐ€ ์ž˜๋ชป ์ถœ๋ ฅ๋˜๋Š” ๊ฒƒ์ด๋‹ค.

์›๋ž˜๋Œ€๋กœ๋ผ๋ฉด, page๋Š” 3์ด์–ด์•ผํ•˜๊ณ  totalElements๋Š” 14๊ฐœ์ด๋ฉฐ totalPages๋Š” 3์ด ์ถœ๋ ฅ์ด ๋˜์–ด์•ผ ํ•˜๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

 

 

public class CustomCommentRepositoryImpl implements CustomCommentRepository {
   private final JPAQueryFactory queryFactory;

   public CustomCommentRepositoryImpl(JPAQueryFactory queryFactory) {
      this.queryFactory = queryFactory;
   }

   @Override
   public Page<CommentDto.Response> findComment(long boardId, Pageable pageable) {

      List<CommentDto.Response> result = queryFactory
         .select(Projections.fields(CommentDto.Response.class,
            comment.board.boardId,
            comment.commentId,
            comment.nickName,
            comment.content,
            comment.createdAt,
            comment.modifiedAt))
         .from(comment)
         .where(comment.board.boardId.eq(boardId))
         .orderBy(comment.commentId.desc())
         .offset(pageable.getOffset())
         .limit(pageable.getPageSize())
         .fetch();

      return new PageImpl<>(result);
   }
}

๊ณฐ๊ณฐํžˆ ์ฝ”๋“œ๋ฅผ ๋ณด๋ฉฐ ์ƒ๊ฐํ•ด๋ณด๋‹ˆ, ํŽ˜์ด์ง€์— ๋Œ€ํ•œ ์ •๋ณด๊ฐ€ ์ž˜ ๋“ค์–ด๊ฐ€์ง€ ์•Š์€ ๊ฒƒ์ด ์•„๋‹๊นŒ ์‹ถ์—ˆ๋‹ค.

๊ทธ๋ž˜์„œ PageImpl ํด๋ž˜์Šค๋ฅผ ๋ณด๊ณ  pageable ์ •๋ณด๋ฅผ ๋„ฃ์–ด์ฃผ์—ˆ๋‹ค.

๊ทธ๋žฌ๋”๋‹ˆ ๋งˆ์ง€๋ง‰์ธ ์„ธ๋ฒˆ์งธ ํŽ˜์ด์ง€์—์„œ๋Š” ์ž˜ ์ถœ๋ ฅ์ด ๋˜์—ˆ๋‹ค. 

ํ•˜์ง€๋งŒ! ๋‘ ๋ฒˆ์งธ ํŽ˜์ด์ง€๋ฅผ ๋ณด๋ฉด ์ž˜ ๋œ ๊ฒƒ์ด ์•„๋‹ˆ์—ˆ๋‹ค.

์•„๋ž˜์˜ ์˜ค๋ฅธ์ชฝ ์‚ฌ์ง„์„ ์ฐธ๊ณ ํ•˜๋ฉด totalElements๊ฐ€ 10๋กœ ๋‚˜์˜ค๋Š” ๊ฒƒ์„ ์•Œ ์ˆ˜ ์žˆ๋‹ค.

์™ผ์ชฝ์€ ์„ธ ๋ฒˆ์งธ ํŽ˜์ด์ง€์˜ ์‚ฌ์ง„, ์˜ค๋ฅธ์ชฝ์€ ๋‘ ๋ฒˆ์งธ ํŽ˜์ด์ง€์˜ ์‚ฌ์ง„

public class CustomCommentRepositoryImpl implements CustomCommentRepository {
   private final JPAQueryFactory queryFactory;

   public CustomCommentRepositoryImpl(JPAQueryFactory queryFactory) {
      this.queryFactory = queryFactory;
   }

   @Override
   public Page<CommentDto.Response> findComment(long boardId, Pageable pageable) {

      List<CommentDto.Response> result = queryFactory
         .select(Projections.fields(CommentDto.Response.class,
            comment.board.boardId,
            comment.commentId,
            comment.nickName,
            comment.content,
            comment.createdAt,
            comment.modifiedAt))
         .from(comment)
         .where(comment.board.boardId.eq(boardId))
         .orderBy(comment.commentId.desc())
         .offset(pageable.getOffset())
         .limit(pageable.getPageSize())
         .fetch();

	  /* pageable ์ •๋ณด ์ถ”๊ฐ€ ๋ฐ ๋ฆฌ์ŠคํŠธ ์‚ฌ์ด์ฆˆ ์ถ”๊ฐ€ */
      return new PageImpl<>(result, pageable, result.size());
   }
}

๊ทธ๋ž˜์„œ ๊ตฌ๊ธ€๋ง์„ ํ•ด๋ณด์•˜๋‹ค.

๊ทธ๋Ÿฌ๋ฉด์„œ SpringFramework์— ํŽ˜์ด์ง• ์ฒ˜๋ฆฌ๋ฅผ ๋„์™€์ฃผ๋Š” ํด๋ž˜์Šค๊ฐ€ ์žˆ๋‹ค๋Š” ๊ฒƒ์„ ์•Œ์•˜๋‹ค.

๋ฐ”๋กœ PageableExecutionUtils์ด์—ˆ๋‹ค.

๊ทธ๋ž˜์„œ ์ฐพ์•„๋ณธ ํ›„ ํ•ด๋‹น ํด๋ž˜์Šค๋ฅผ ์ ์šฉ์‹œ์ผœ์ฃผ์—ˆ๋‹ค.

ํ•˜์ง€๋งŒ ํ•ด๋‹น ๋ฌธ์ œ๋Š” ํ•ด๊ฒฐ๋˜์ง€ ์•Š์•˜๋‹ค.

 

์กฐ๊ธˆ ๋” ์˜ˆ์‹œ๋ฅผ ์ฐพ์•„๋ณธ ๊ฒฐ๊ณผ JPAQuery๋ฅผ ํ†ตํ•ด ํŽ˜์ด์ง€ ๊ฐ’์„ ์ฐพ์„ ์ˆ˜ ์žˆ๋Š” ์˜ˆ์‹œ๋ฅผ ๋ฐœ๊ฒฌํ•˜์˜€๋‹ค.

๊ทธ๋ž˜์„œ ํ•ด๋‹น ๋ถ€๋ถ„์„ ์ ์šฉ์‹œ์ผœ ๋ณธ ๊ฒฐ๊ณผ ํ•ด๊ฒฐ์ด ๋˜์—ˆ๋‹ค.

 

public class CustomCommentRepositoryImpl implements CustomCommentRepository {
   private final JPAQueryFactory queryFactory;

   public CustomCommentRepositoryImpl(JPAQueryFactory queryFactory) {
      this.queryFactory = queryFactory;
   }

   @Override
   public Page<CommentDto.Response> findComment(long boardId, Pageable pageable) {

      List<CommentDto.Response> result = queryFactory
         .select(Projections.fields(CommentDto.Response.class,
            comment.board.boardId,
            comment.commentId,
            comment.nickName,
            comment.content,
            comment.createdAt,
            comment.modifiedAt))
         .from(comment)
         .where(comment.board.boardId.eq(boardId))
         .orderBy(comment.commentId.desc())
         .offset(pageable.getOffset())
         .limit(pageable.getPageSize())
         .fetch();

	  /* ์•„๋ž˜์˜ ์ฝ”๋“œ๋„ ๊ฐ€๋Šฅ
      JPAQuery<Comment> total = queryFactory.selectFrom(comment)
			.where(comment.board.boardId.eq(boardId));
      */

	  JPAQuery<CommentDto.Response> total = queryFactory
         .select(Projections.fields(CommentDto.Response.class,
            comment.board.boardId,
            comment.commentId,
            comment.nickName,
            comment.content,
            comment.createdAt,
            comment.modifiedAt))
         .from(comment)
         .where(comment.board.boardId.eq(boardId));

      return PageableExecutionUtils.getPage(result, pageable, () -> total.fetch().size());
   }
}

์—ฌ๊ธฐ์„œ ๋˜ ๋‹ค๋ฅธ ์˜๋ฌธ์ด ์ƒ๊ฒผ๋‹ค.

fetch๋ฅผ ํ•˜๊ณ  size๋ฅผ ๊ตฌํ•˜๋Š” ๊ฒƒ์ด๋ฉด, JPAQuery๋ฅผ ์ด์šฉํ•ด ๋‹ค ๊ฐ€๋Šฅํ•˜์ง€ ์•Š์„๊นŒ ํ•˜๋Š” ๊ฒƒ์ด๋‹ค.

ํ•˜์ง€๋งŒ ์ด์ƒํ•˜๊ฒŒ๋„ ๊ทธ๋ ‡๊ฒŒ ํ•˜๋ฉด, ์•„๊นŒ ์ƒ๊ฒผ๋˜ ๋ฌธ์ œ ์ฒ˜๋Ÿผ ๋‘ ๋ฒˆ์งธ ํŽ˜์ด์ง€์—์„œ ์ œ๋Œ€๋กœ ์ถœ๋ ฅ๋˜์ง€ ์•Š๋Š” ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•˜์˜€๊ณ ,

์‹ฌ์ง€์–ด๋Š” totalPages๋„ 2ํŽ˜์ด์ง€๋กœ๋งŒ ๋œจ๋Š” ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•˜์˜€๋‹ค.

public class CustomCommentRepositoryImpl implements CustomCommentRepository {
   private final JPAQueryFactory queryFactory;

   public CustomCommentRepositoryImpl(JPAQueryFactory queryFactory) {
      this.queryFactory = queryFactory;
   }

   @Override
   public Page<CommentDto.Response> findComment(long boardId, Pageable pageable) {

      JPAQuery<CommentDto.Response> total = queryFactory
         .select(Projections.fields(CommentDto.Response.class,
            comment.board.boardId,
            comment.commentId,
            comment.nickName,
            comment.content,
            comment.createdAt,
            comment.modifiedAt))
         .from(comment)
         .where(comment.board.boardId.eq(boardId))
         .orderBy(comment.commentId.desc())
         .offset(pageable.getOffset())
         .limit(pageable.getPageSize());

      return PageableExecutionUtils.getPage(total.fetch(), pageable, () -> total.fetch().size());
   }
}

์•„์ง ๊ฐ•์˜๋ฅผ ์ด ๊ณณ๊นŒ์ง€ ๋‹ค ๋“ฃ์ง€ ๋ชปํ–ˆ๊ธฐ ๋•Œ๋ฌธ์— ์กฐ๊ธˆ ๋” ๊ณต๋ถ€ํ•ด๋ณด๊ณ , ์ด์œ ๋ฅผ ์ฐพ๋Š”๋‹ค๋ฉด ํ™•์‹คํžˆ ๊ธฐ๋ก์„ ํ•ด๋‘์–ด์•ผ ๊ฒ ๋‹ค!


 

๋Œ“๊ธ€