티스토리 뷰

이용자의 입장에서 바라봤을 때 내가 필요한 게시글이 페이지 번호2번과 3번사이에 있으면 그 쯤에서 찾으면 되는데 

하염없이 쭉 늘어져 있으면 내가 필요한 글의 제목 작성자 내용등을 일일히 알고 있어야 하거나 게시글 하나하나 들어가보며 찾아야 합니다.

이용자의 입장에선 굉장히 불편하기도 하고 사용하기 싫어질수 있습니다.

또한 수많은 데이터를 한 페이지에서 보여주면, 처리 성능 면에서도 영향을 미칠 것입니다.

 

그렇기에 백앤드 웹개발에서 페이징은 필수 인것 같아 페이징을 공부하면서 정리할겸 기록을 남기기로 했습니다.

 

아래의 SQL쿼리문은 페이지당 10개의 게시물을 띄우고 2개의 페이지로 나누고 싶을때의 SQL쿼리문입니다.

※ 게시물을 기준으로 보통 최신글이 가장 위에 올라온다. 즉 가장 늦게 들어온 데이터가 가장 첫번째로 올라와야한다.

 

(1) 페이지 1 = 가장 최근 10개의 게시물 확인

select /*+ INDEX_DESC (tbl_board pk_board)*/ 
    ROWNUM rn, bno, title, content 
    from 
    tbl_board 
    WHERE rownum <= 10;

 

(2)페이지 2 = 가장 최근 20개의 게시물 확인

select rn, bno, title, content 
    from
    (select /*+ INDEX_DESC (tbl_board pk_board)*/ 
        ROWNUM rn, bno, title, content 
        from 
        tbl_board 
        WHERE rownum <= 20
    )
    where rn > 10;

 

과정 설명

• 필요한 순서로 정렬된 데이터에 rownum을 붙입니다. 

   rownum은 테이블에서 데이터를 가져오면 그 데이터들의 첫번째부터 순서대로 붙는 번호입니다.(1부터 시작)

• 처음부터 해당 페이지의 데이터를 'rownum'을 통해서 정렬합니다.

• 구해 놓은 데이터를 하나의 테이블(view)로 생각하고 인라인 뷰로 처리한다음 필요한 데이터만을 남깁니다.

 

우선 페이지 2를 왜 인라인뷰로 처리하는지 알아야합니다.

select /*+ INDEX_DESC (tbl_board pk_board)*/ 
    ROWNUM rn, bno, title, content 
    from 
    tbl_board WHERE rownum <= 20;

위 코드를 작동시키면 일단 1번째 페이지와 2번째 페이지의 데이터들이 다 들어있습니다.

첫번째 페이지는 페이지 1처럼 rownum <= 10을 해서 나왔지만

두번재 페이지는 위코드처럼 작동시키면 1번째 페이지 + 두번째 페이지까지 같이 나와버려 1번째 페이지의 데이터가 중복되어 나오게 됩니다.

 

아그러면 1번째 페이지와 2번째 페이지사이의 데이터만 나오게 하면되겠구나?

select /*+ INDEX_DESC (tbl_board pk_board)*/ 
    ROWNUM rn, bno, title, content 
    from tbl_board 
    WHERE rownum > 10 and rownum >= 20;

위 코드를 작동시키면 아무런 값도 나오지 않게 됩니다.

why?

rownum은 처음으로 나오는 값이 1입니다.

하지만 where절에 의해 rownum>10이라는 조건에 의해 무효화 됩니다.

그렇게 되면 이제 다음 데이터가 오게 되는데 그 데이터 또한 첫번째 데이터가 되므로 그것또한 rownum은 1이 됩니다.

이렇게 반복되어서 아무런 값이 나오지 않게 되는 것입니다.

 

그렇기 때문에 구해 놓은 데이터를 하나의 테이블(view)로 생각하고(인라인 뷰) 처리한다음 필요한 데이터만을 남기는 것입니다.

 

 

만약 게시글이 20개로 지정되어있고 새로운 글을 추가하고 오래된 글은 보이지 않게 하려면 위 방법을 그대로 사용해도 됩니다.

하지만 게시물•게시글은 계속해서 추가 되는것이고 추가 됨에 따라 페이지의 데이터도 계속 늘어날것이고

계속해서 확장을 하기 때문에 확장성을 고려하 설계를 해야합니다.

 

 

Criteria 클래스 작성

    ※ 페이징 처리를 위해서 필요한 파라미터

        1. 페이지 번호(pageNum)

        2. 한페이지당 몇 개의 데이터를 보여줄것인가(amount)

package com.startcoriny.domain;

import lombok.Getter;
import lombok.Setter;
import lombok.ToString;

@Getter
@Setter
@ToString
public class Criteria { // 용도 : pageNum과 amount 값을 같이 전달하는 용도

	private int pageNum;
	private int amount;
	
	public Criteria() { //기본값 : 1페이지, 10개의 게시물
		this(1,10);
	}
	
	public Criteria(int pageNum, int amount) {
		
		this.pageNum = pageNum;
		this.amount = amount;
		
	}
	
}

테스트를 위해 기본값을 정해줍니다.(현재 100개의 게시물 수용가능)

 

 

BoarderMapper interface작성

package com.startcoriny.mapper;

import java.util.List;

import com.startcoriny.domain.BoardVO;
import com.startcoriny.domain.Criteria;

public interface BoardMapper {

	public List<BoardVO> getListWithPaging(Criteria cri);

}

스프링에서 MyBatis를 통해 XML로 처리하기 때문에  XML과 연결되는 메서드를 작성합니다.

 

 

mapping쿼리문 작성

	<select id="getListWithPaging" resultType="com.startcoriny.domain.BoardVO">
		<![CDATA[
			select rn, bno, title, content, writer, regdate, updatedate 
			from
				(select /*+ INDEX_DESC (tbl_board pk_board)*/ 
				    ROWNUM rn, bno, title, content, writer, regdate, updatedate 
				    from 
				        tbl_board 
				    WHERE rownum <= 20
				)
			where rn > 10	
		]]>
	</select>

여기서 Mybatis의 XML에 CDATA처리가 들어갑니다.

Why?


CDATA섹션은 XML 에 사용할 수 없는 부등호를 사용하기 위함입니다.

XML에서 '<' 나 '>'는 태그로 인식을 합니다. 물론 &lt;나 &gt; 같은 특수 문자를 사용할수도 있습니다. 

하지만 더 편리함과 가독성을 위해서, 태그로 인식하는 문제를 막기위해서 CDATA섹션을 사용합니다.

 

위 쿼리문의 문제는 확장이 되지 않는다는 것입니다.

하지만 쉽게 생각해볼수 있습니다.

인라인 뷰 안의 rownum <= 20선택한 페이지의 번호 * 데이터의 수 입니다. 

즉, 내가 선택한 페이지의 번호(pageNum) * 한 페이지의 얼만큼의 데이터를 보여줄것인가(amount) 가 되는 것입니다.

2번째 페이지 번호를 클릭 했을 때 인라인 뷰 안에는 총 20개의 데이터가 있어야 합니다.

3번째 페이지 번호를 클릭 했을 때 인라인 뷰 안에는 총 30개의 데이터가 있어야 하구요.

 

그럼 이제 3번째 페이지를 클릭했을 때 21~30번까지의 데이터를 가져와야 합니다.

2번째 페이지를 선택하고 데이터의 수는 10개로 가정했을 때

이전페이지의 게시물 갯수 10개를 제외해야 하므로 10 x 첫번째 페이지

 

즉, where조건절의 rn > 10에서 10보여질 데이터의수(amount) * 이전 페이지 입니다.

 

위 Criteria 클래스에서 기본값을 10으로 초기화 했기 때문에 현재도 10으로 저장되어 있습니다.

이렇게 되면 amount(10) * [      ] = 20 이 되어야 rn은 20 초과가 되어 21부터 30가지 나올수가 있습니다 .

여기서 2를 곱하게 되면 20이 나오게 되는데 2라는 숫자는

내가 현재 선택한 페이지 번호(pageNum)-1을 하면 2라는 숫자가 나옵니다.

pageNum(3) - 1 = 2

 

그럼 2번째 페이지를 클릭했을 때 작동을 다시 돌아가보면

인라인 뷰 안쪽의 rownum <= 20 여기서 20은 pageNum(2) * amount(10) = 20

where 절의 rownum > 10 여기서 10은 (pageNum(2) - 1) * 10 = 10 으로 확장이 된걸 확인 할수 있습니다.

 

즉, 최종 xml쿼리문은

	<!-- 게시글 리스트 및 페이징 -->
	<select id="getListWithPaging" resultType="com.startcoriny.domain.BoardVO">
		<![CDATA[
			select rn, bno, title, content, writer, regdate, updatedate 
			from
				(select /*+ INDEX_DESC (tbl_board pk_board)*/ 
				    ROWNUM rn, bno, title, content, writer, regdate, updatedate 
				    from 
				        tbl_board 
				    WHERE rownum <= #{pageNum} * #{amount}
				)
			where rn > (#{pageNum}-1)*#{amount}			
		]]>
	</select>

이제 4페이지 5페이지를 가도 해당 페이지의 해당하는 데이터를 확인 할수 있게 됐습니다.

 

 

 

 

 

 

배워나가는 코린이 입니다!!

부족한게 있다면 댓글로 지적해주세요!! 감사합니다!😊

'프로그래밍 기초 > Spring' 카테고리의 다른 글

게시판 페이징 처리(2)  (2) 2023.12.15
한글 깨짐 현상 해결  (0) 2023.11.30
프로젝트 절대 경로 설정  (0) 2023.11.30
의존성 주입이란?  (0) 2023.11.23
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
«   2024/09   »
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
글 보관함