sitelink1  
sitelink2  
sitelink3  
sitelink4  
sitelink5  
sitelink6  
나는 페이징 관련 프로그래밍을 해본적이 별로 없다.
사실 페이징 로직은 초기 개발할때나 연구하는거지 이렇게 유지보수성 일들을 하다보면 다양하게 접할 기회가 그리 많지가 않다.
작년 사내프로젝트를 수행하면서 당연히 만들게 되는 게시판에서 페이징 처리에 대해 일주일정도 고민을 했던 기억이 나지만 그 이전에는
공부할때 게시판 만들었던 것 빼고는 기억이 나지 않는다.
그래서... 작년에도 그리고 올해에도 나는 똑같은 삽질을 하고 있었다.
쿼리문을 작성할때 필요한 것은 데이터의 가공을 어떤식으로 처리할까를 머리속에 그려보는 것이다.
하지만 시간이 지날수록 내 머리는 굳어만가고 더이상 생각하기 귀찮아를 연발하면서 일을 해결하기 위해서 겨우 겨우 작은 힌트들을 쫓아가고 있었다.
그리고 결국은 쿼리의 작성도 자동화 해야 겠다는 생각이 들었다.

쿼리문을 작성하는데 필요한 요소는 다음과 같다.

1. 최종적으로 뽑아내게 될 필드 리스트
2. 원하는 데이터 리스트를 추출하게 될 테이블 또는 뷰
3. 조건문, 정렬문 등의 적절한 위치

등이 있다.

페이징 로직에 대한 고민을 하면서 한가지 발견한 특이점은 내가 원하는 결과물을 얻기 위해 나도 모르게 쿼리를 가공하면서 인라인 뷰 형태로 쿼리를 감싸고 있다는 것이었다.
가령 원래의 전체 데이터 리스트 (VIEW)가 존재한다면, 이 리스트에 검색조건을 적용하기 위해 쿼리문 뒤에 WHERE문을 덧붙이지만
그 이전에 데이터 리스트가 WHERE문에 적합하도록 가공이 되어 있어야 하기 때문에 SearchQuery = [SELECT * FROM (VIEW) searchmytable WHERE 검색조건] 식으로 쿼리를 덧 씌우는 형태로 만들게 된다.
여기에 소트정보를 적용한다면 SortQuery = [SELECT * FROM (SearchQuery) sortmytable ORDER BY 정렬조건] 이러한 형태로 가공하면서 점점 쿼리를 덧 씌우게 된다.
물론 위와 같이 쿼리를 덧 씌우는 방식은 DB에 부담을 주는 매우 나쁜 쿼리이다.
하지만 성능 좋은 쿼리를 작성하기 위해 고민하기 이전에 간단한 쇼핑몰이나 만들면서 대용량 데이터베이스에서나 적용할만한 쿼리를 작성하기 위해 너무나 많은 시간을 허비하는 것은 무의미한 행위라고 생각하였다.
그래서 위의 쿼리 작성방식을 자동화해 줄 코드를 작성하기로 마음 먹었다.
queryhelper.gif

대략 클래스들의 이름만 봐도 뭘 하려고 하는지 짐작할 수 있을거라 생각한다.
AttachQuery 클래스는 QueryInfo클래스의 객체(소스가 되는 쿼리정보) 또는 AttachQuery클래스의 객체를 생성자의 파라미터로 받아서 저장후 이를 가공하게 되며,
AttachQuery를 상속받는 클래스들은 동일한 속성을 갖게 되어 객체 생성시 AttachQuery 객체를 생성자의 파라미터로 저장이 가능해서 원하는 형태로 쿼리의 중첩을 실현 가능하게 해준다.
이 클래스들을 작성하는데에 적용한 패턴은 데코레이터 패턴으로 자바 I/O 패키지의 특징을 본따서 만들었다.
AttachQuery는 기본적으로 public abstract String getQueryString(); 추상 메서드를 가지고 있기 때문에 이 클래스를 상속받아 작성하는 클래스들은 이 추상메서드를 구현해야 한다.
QueryInfo는 쿼리문을 작성하는데에 필요한 구성 요소들을 변수로써 가지는 빈 객체이다.
AttachQuery 클래스를  상속받아 구현한 서브클래스중 AttachSearchInfoQuery클래스를 살펴보면 다음과 같다.

·미리보기 | 소스복사·
 
  1. public class AttachSearchInfoQuery extends AttachQuery {   
  2.   
  3.     public AttachSearchInfoQuery(PagingQueryInfo pagingqueryInfo) {   
  4.         super(pagingqueryInfo);   
  5.     }   
  6.        
  7.     public AttachSearchInfoQuery(AttachQuery attachQuery) {   
  8.         super(attachQuery);   
  9.     }   
  10.        
  11.     public String getQueryString() {   
  12.         AttachQuery attachQuery = getAttachQuery();   
  13.         PagingQueryInfo pagingQueryInfo = getPagingQueryInfo();   
  14.         String queryString = attachQuery.getQueryString();   
  15.            
  16.         if(!pagingQueryInfo.getSearchCondition().equals("")) {   
  17.             String queryHead = "";   
  18.             String queryFoot = "";   
  19.                
  20.             if(!QueryUtil.isTable(queryString)) {   
  21.                 queryHead = "SELECT "+ pagingQueryInfo.getFieldList() +" FROM (";   
  22.                 queryFoot = ") searchmytable "+ pagingQueryInfo.getSearchCondition();   
  23.             } else {   
  24.                 queryHead = "SELECT "+ pagingQueryInfo.getFieldList() +" FROM ";   
  25.                 queryFoot = " "+ pagingQueryInfo.getSearchCondition();   
  26.             }   
  27.             queryString = queryHead + queryString + queryFoot;   
  28.             printQuery(this.getClass().getName(), queryHead, queryFoot);   
  29.         }   
  30.   
  31.         return queryString;        
  32.     }   
  33.        
  34.     public void setSearchCondition(String searchCondition) {   
  35.         getPagingQueryInfo().setSearchCondition(searchCondition);   
  36.     }   
  37.        
  38. }  

위의 코드와 같이 AttachQuery클래스를 상속받음으로써 getQueryString() 추상 메서드를 구현하고 있으며 getQueryString() 추상 메서드 내부에서 사용하는 메서드들은 AttachQuery 추상 클래스에서 미리 정의해 놓은 메서드들로써 다음과 같은 용도로 사용된다.
    - getAttachQuery() 메서드는 현재까지 작성해오던 쿼리 정보를 내포하는 AttachQuery 객체를 얻어온다.
    - getPagingQueryInfo() 메서드는 현재 작성해야 할 단계에서 필요한 정보를 얻어오기 위해 미리 저장된 PagingQueryInfo 객체를 얻어온다.

이것은 쿼리를 작성하는 패턴이 변화되거나 추가해야 할 클래스가 존재하게 된다면 단지 AttachQuery추상 클래스를 구현하는 서브클래스를 추가해서 구현해 나가는 방식으로 하나의 집합체를 구성하게 되며,
각 서브클래스들은 지금은 수평관계에 있지만 때에 따라서는 수직관계로도 확장이 가능하다. (자바 I/O패키지를 연상하면 쉽다)
이를 이용하여 쿼리를 작성하는 코드로 실제 적용한 부분은 PagingQueryHelper라는 추상 클래스로써 public abstract String getRecordsQuery(int start, int end); 추상 메서드를 서브클래스에서 구현해야 하는 클래스이다.
이를 서브클래스로써 구현한 클래스는 PagingQueryHelperForMysql 라는 클래스와 PagingQueryHelperForOracle 라는 클래스 두가지를 만들어 두었다.
이 클래스들 역시 내가 원하는 쿼리를 리턴 받기 위한 최종 목적지는 아니고, 이 클래스들을 이용하여 쿼리를 만드는 예제는 SimplePagingTestServlet클래스의 viewListForMysql()메서드를 살펴보면 된다.

·미리보기 | 소스복사·
 
  1. String[] fieldArray = {"productid""listprice""unitcost""supplier""attr1"};   
  2. PagingQueryInfo pagingQueryInfo = new PagingQueryInfo(fieldArray);   
  3. pagingQueryInfo.setSchema("ITEM"); // 페이징 처리를 하고 싶은 목록 테이블 또는 쿼리 ([ex> select listprice from tab])   
  4. pagingQueryInfo.setRowNumAlias("rnum"); // rownum의 별명   
  5. pagingQueryInfo.setSearchCondition(new SearchInfoForMysql(req).getSearchCondition()); // 검색 정보 셋팅   
  6. pagingQueryInfo.setSortCondition(new SortInfoForMysql(req).getSortCondition()); // 정렬 정보 셋팅   
  7. args.put("pagingQueryHelper"new PagingQueryHelperForMysql(pagingQueryInfo));  


생성자 부분에서 PagingQueryInfo 클래스 객체를 작성하여 PagingQueryHelperForMysql 클래스 생성자의 인자로 객체를 생성하면 , getRecordCountQuery() 메서드로는 전체 레코드 갯수를 질의하는 쿼리를 작성하고, getRecordsQuery(start, end) 메서드로는 범위 레코드 리스트를 질의하는 쿼리를 작성하게 된다.

번호 제목 글쓴이 날짜 조회 수
103 J2SE 5.0 - 제네릭(GENERIC) 황제낙엽 2007.08.27 389
102 Cookie Test file 황제낙엽 2007.08.27 280
101 쿠키 유틸리티 클래스 CookieBox 만들기 file 황제낙엽 2007.08.27 420
100 통합을 위한 요소 기술, Java와 XML 황제낙엽 2007.08.27 419
99 중복 로그인 제한 기법에 대하여 황제낙엽 2007.08.23 457
98 interface와 abstract클래스의 차이점 황제낙엽 2007.07.28 520
97 javadoc - The Java API Documentation Generator 황제낙엽 2007.07.25 574
96 자바의 I/O 예제 [3] file 황제낙엽 2007.07.16 454
95 자바의 I/O 예제 [2] file 황제낙엽 2007.07.14 292
94 계층형(답변형) 게시판 로직(최근 답변 하단으로) 황제낙엽 2007.07.11 434
93 J2SE 5.0 - 주석(annotation,표식) 개요 황제낙엽 2007.07.03 393
92 include문과 logging 설정 황제낙엽 2007.03.23 551
91 [BPP] 게시판 페이징 로직 분석 - M1.1 - 샘플 다운로드 및 사용법 file 황제낙엽 2007.06.15 440
90 [BPP] 게시판 페이징 로직 분석 - (5) 페이지 계산 file 황제낙엽 2007.06.15 438
» [BPP] 게시판 페이징 로직 분석 - (4) 쿼리문의 자동완성 file 황제낙엽 2007.06.14 489
88 [BPP] 게시판 페이징 로직 분석 - (3) 검색과 정렬 file 황제낙엽 2007.06.13 354
87 [BPP] 게시판 페이징 로직 분석 - (2) 간단한 페이징 기법 황제낙엽 2007.06.08 826
86 [BPP] 게시판 페이징 로직 분석 - (1) 클래스 목록 file 황제낙엽 2007.06.06 393
85 문자열의 앞뒤space제거처리 성능체크 황제낙엽 2007.06.03 418
84 간단한 서블릿 예제들 file 황제낙엽 2007.05.12 323