JSP & Servlet

다시 확인하는 Paging 처리

Jungsoomin :) 2020. 8. 29. 19:11

 

 

기본적으로, amount = 양 / pageNum = 현재 사용자의 페이지 를 기준으로 원하는 만큼의 데이터를 꺼내오는 작업을 거친다. 정렬은 데이터추출 속도에 상당히 치명적이므로, 이미 정렬되어있는 Index를 기준하여 실행계획을 수립하도록 해야한다.

 

Oracle DATABASE 의 경우, 가져온데이터에 따른 번호를 매기는 ROWNUM 이 제공되는데,

 

이를 이용할떄에 Rownum 추출은 반드시 1을 포함하는 작업을 거쳐야함으로.(인덱스에 맞는 rowid 값의 데이터 접근 및 추출 후 ROWNUM 부여 의 과정을 반복하는 듯 하다.)

 

SELECT /*+ INDEX_DESC(테이블명 인덱스명) */ ROWNUM rn , 컬럼명... 
FROM 테이블명 WHERE ROWNUM <= 원하는 범위

 

이런식으로 오라클 힌트로 실행계획에 정렬을 피하며, ROWNUM 에 별칭을 주어 바깥 쿼리문에서 RN이라는 이름으로 잘라낼 수 있게끔 해준다. 

 

별칭을 준 이유의 의미는, 바깥 쿼리문 추출에서의 ROWNUM 값과의 충돌을 회피하기 위해서라고 생각한다.


SELECT 컬럼명... FROM
	(SELECT /*+ INDEX_DESC(테이블명 컬럼명) */ ROWNUM RN , 컬럼명... 
    FROM 테이블명 WHERE ROWNUM <= 원하는 추출범위)
WHERE RN > 잘라낼 추출범위

안쪽 인라인 뷰로 VIEW를 생성하고 바로 이를 이용해 셀렉트를 하는데, 안쪽 쿼리로 1부터 가져올 값을 추출하고,

 

바깥쪽 쿼리문으로 원하는 값만큼 잘라 추출하는 듯 하다.


이를 MyBatis에서 처리하게 된다면 이렇게.. 페이지 파라미터를 받아 원하는 페이지의 양의 데이터만큼을 잘라 리턴한다.

SELECT 컬럼명... FROM
	(SELECT /*+ INDEX_DESC(테이블명 컬럼명) */ ROWNUM RN , 컬럼명... 
    FROM 테이블명 WHERE ROWNUM <= #{pageNum} * #{amount} )
WHERE RN > (#{pageNum} - 1) * #{amount}

그리고나서는 View 단에서의 PageNation 이 필요하다.

  1. 현재 사용자의 페이지 넘버

  2. 이전과 다음으로 가는 버튼의 표시여부

  3. 화면에서 나오는 페이지의 시작 번호 , 마지막번호

좋은 접근은, 현재 사용자의 페이지 번호를 기준으로 마지막번호부터 추출해내는 것이다.

this.endPage = (int)
(Math.ceil(현재페이지번호 / 화면에 보여줄 페이지번호 의 수 * 1.0 ) * 화면에 보여줄 페이지번호 의 수);

즉, 7의 페이지가 현재페이지이고, 보여줄 페이지번호의 양이 5라면  >  7/5.0 * 5 = 1.4의 올림 값 * 5 = 10 이므로,  보여줄 마지막 번호는 10이 된다.

 

하지만, 언제나 데이터의 양이 amount 의 단위로 딱 떨어질 수는 없는 것이기 때문에. 변경의 여지가 있다고 봐야한다.

 


이제, 시작번호를 얻는데, 이 과정은 전보다 간단하다.

this.startPage = this.endPage - (화면에 보여줄 페이지번호의 수 -1) ;

10 - (5-1) = 6 이 보여줄 시작번호가 된다.

 


마지막 번호의 개선 점은, amount 와 endPage의 곱이 전체데이터인 total 보다 클경우 total이 endPage가 된다.

realEnd = (int)(Math.ceil( ((total * 1.0) / amount)) ); // 먼저 계산 처리 후 올림

if(realEnd < this.endPage) {
	this.endPage = realEnd;
}
  1. 아까처럼 10이 마지막 페이지라면 total은 50이다. 그런데 total이 44개라면, 

  2. realEnd = 44 * 1.0 / amount <<자바 ...의 프로모션으로인한 곱셉.

  3. 즉 8.8 의 올림 값이므로 realEnd 는 9가 된다. 이는 처음에 도출된 endPage 보다 작은 수 이므로

  4. endPage = 9로 바뀌게 설정되는 것 같다.


이전과 다음 버튼은, 사용자의 현재 페이지에 따른 도출 번호에 맞게 설정해주면 된다.

this.prev = this.startPage > 1
this.next = this.endPage < realEnd;

이후에 적절한 클래스를 이용하여 생성자를 만들어서, 현재 페이지를 기준으로  정보를 얻어내어 해당 인스턴스 멤버들의 값을 변경해주면, PageNation을 위한 객체가 만들어 질 것이다.

 


endPage를 조작해서 현재 페이지 번호부터 마지막 페이지의 번호 개수를 원하는대로 조작할 수 있다. 

endPage= pageNo + (int)(보여주고싶은 번호 개수 / 2 - 1); //  현재페이지 기준 + 4 만큼의 엔드페이지 번호 설정
		
//		endPage = (int)(Math.ceil(pageNo / 보여주고싶은 번호 개수) * 보여주고싶은 번호 개수); 10개식 고정방식.
		startPage = endPage - ((int)PAGING_BTN_COUNT -1);
		if(startPage < 1) {// 마지막 페이지 번호 변경으로 인한 제어
			startPage = 1;
		}