1. emp list 페이징을 구현하시오.

1-1-1. 소스코드(Criteria 객체)

package edu.bit.ex.emp.page;

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

@ToString
@Setter
@Getter
public class Criteria {
	private int pageNum;
	private int amount;

	public Criteria() {
		this(1, 10);
	}

	public Criteria(int pageNum, int amount) {
		this.pageNum = pageNum;
		this.amount = amount;
	}
}

 

1-1-2. 소스코드(PageVO 객체)

package edu.bit.ex.emp.page;

import org.springframework.web.util.UriComponents;
import org.springframework.web.util.UriComponentsBuilder;

import lombok.Getter;
import lombok.ToString;

@Getter
@ToString
public class PageVO {
	private int startPage;
	private int endPage;
	private boolean prev, next;

	private int total;
	private Criteria cri;

	public PageVO(Criteria cri, int total) {
		this.cri = cri;
		this.total = total;

		this.endPage = (int) (Math.ceil(cri.getPageNum() / 10.0)) * 10;
		this.startPage = this.endPage - 9;

		int realEnd = (int) (Math.ceil((total * 1.0) / cri.getAmount()));
		if (realEnd <= this.endPage) {
			this.endPage = realEnd;
		}

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

	public String makeQuery(int page) {
		UriComponents uriComponentsBuilder = UriComponentsBuilder
            							 .newInstance()
            							 .queryParam("pageNum", page)
									    .queryParam("amount", cri.getAmount())
            							 .build();
		return uriComponentsBuilder.toUriString();
	}
}

 

1-1-3. 소스코드(Controller 객체)

package edu.bit.ex.emp.controller;

import javax.validation.Valid;

import org.springframework.stereotype.Controller;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;

import edu.bit.ex.emp.page.Criteria;
import edu.bit.ex.emp.page.PageVO;
import edu.bit.ex.emp.service.EmpService;
import edu.bit.ex.emp.vo.EmpVO;
import lombok.AllArgsConstructor;
import lombok.extern.log4j.Log4j;

@Log4j
@AllArgsConstructor
@Controller
public class EmpController {
	private EmpService empService;

	// 직원 리스트
	@GetMapping("/emp/list")
	public void list(Model model) {
		model.addAttribute("list", empService.getList());
		log.info("list()");
	}

	// 페이징을 적용한 직원 리스트
	@Transactional
	@GetMapping("/emp/list2")
	public void list2(Criteria cri, Model model) {
		log.info("list2");
		log.info(cri);
		model.addAttribute("list", empService.getList(cri));

		int total = empService.getTotal(cri);
		log.info("total" + total);
		model.addAttribute("pageMaker", new PageVO(cri, total));
	}
    
	...(생략)

}

 

1-1-4. 소스코드(Service 인터페이스)

package edu.bit.ex.emp.service;

import java.util.List;

import edu.bit.ex.emp.page.Criteria;
import edu.bit.ex.emp.vo.EmpVO;

public interface EmpService {
	// 직원정보 리스트
	public List<EmpVO> getList();

	// 페이징을 적용한 직원정보 리스트
	public List<EmpVO> getList(Criteria criteria);

	public int getTotal(Criteria criteria);

	...(생략)
    
}

 

1-1-5. 소스코드(ServiceImpl 객체)

package edu.bit.ex.emp.service;

import java.util.List;

import org.springframework.stereotype.Service;

import edu.bit.ex.emp.mapper.EmpMapper;
import edu.bit.ex.emp.page.Criteria;
import edu.bit.ex.emp.vo.EmpVO;
import lombok.AllArgsConstructor;
import lombok.extern.log4j.Log4j;

@Log4j
@Service
@AllArgsConstructor
public class EmpServiceImpl implements EmpService {
	private EmpMapper mapper;

	// 직원 정보 리스트
	@Override
	public List<EmpVO> getList() {
		log.info("getList()");
		return mapper.getList();
	}

	// 페이징을 적용한 직원 정보 리스트
	@Override
	public List<EmpVO> getList(Criteria criteria) {
		log.info("get List with criteria" + criteria);
		return mapper.getListWithPaging(criteria);
	}

	@Override
	public int getTotal(Criteria criteria) {
		log.info("get total count");
		return mapper.getTotalCount(criteria);
	}

	...(생략)

}

 

1-1-6. 소스코드(BoardMapper 객체)

package edu.bit.ex.emp.mapper;

import java.util.List;

import edu.bit.ex.emp.page.Criteria;
import edu.bit.ex.emp.vo.EmpVO;

public interface EmpMapper {
	// 직원 정보 불러오기
	public List<EmpVO> getList();

	// 페이징을 적용한 직원 정보 불러오기
	public List<EmpVO> getListWithPaging(Criteria criteria);

	public int getTotalCount(Criteria criteria);

	...(생략)

}

 

1-1-7. 소스코드(BoardMapper XML문서)

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
  PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
  "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="edu.bit.ex.emp.mapper.EmpMapper">
	<!-- 전체 직원 정보 리스트 -->
	<select id="getList" resultType="edu.bit.ex.emp.vo.EmpVO">
	<![CDATA[
		SELECT e.empno, e.ename, e.job, e.mgr, e.hiredate, e.sal, e.comm, d.deptno, d.dname, d.loc FROM dept01 d, emp01 e WHERE d.deptno = e.deptno AND e.mgr IN (SELECT employee.mgr FROM emp01 employee, emp01 manager WHERE employee.mgr = manager.empno)
	]]>
	</select>
	
	<!-- 페이징을 적용한 전체 직원 정보 리스트 -->
	<select id="getListWithPaging" resultType="edu.bit.ex.emp.vo.EmpVO">
	<![CDATA[
		SELECT * FROM (SELECT ROWNUM AS RNUM, A.* FROM (SELECT e.empno, e.ename, e.job, e.mgr, e.hiredate, e.sal, e.comm, d.deptno, d.dname, d.loc FROM emp01 e, dept01 d WHERE e.deptno = d.deptno) A WHERE ROWNUM <= #{pageNum}*#{amount}) WHERE RNUM > (#{pageNum}-1)*#{amount}
	]]>
	</select>
	
	<select id="getTotalCount" resultType="int">
		select count(*)	from emp01
	</select>
	
	...(생략)
    
</mapper>

 

1-1-8. 소스코드(list2 JSP파일)

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
    
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>    
    
<!DOCTYPE html>
<head>
    ...(생략)
</head>  
<body id="page-top">
	...(생략)
                  <tbody>            
                  <c:forEach items="${list}" var="dto">
                    <tr>
				        <td>${dto.empno}</td>
				        <td>${dto.ename}</td>
				        <td>${dto.job}</td>
				        <td>${dto.mgr}</td>     
				        <td>${dto.hiredate}</td>		        
				        <td>${dto.sal}</td>
				        <td>${dto.comm}</td>
				        <td>${dto.deptno}</td>
				        <td>${dto.dname}</td>
				        <td>${dto.loc}</td>
				        <td><a href="modify_view?empno=${dto.empno}">관리</a></td>
	      		    </tr>         
                   </c:forEach>
                  
                  </tbody>
                </table>
                
                <c:if test="${pageMaker.prev}">
					<a href="list2${pageMaker.makeQuery(pageMaker.startPage - 1)}">«</a>
				</c:if>

				<c:forEach begin="${pageMaker.startPage }" end="${pageMaker.endPage}" var="idx">
					<c:out value="${pageMaker.cri.pageNum == idx?'':''}" />
					<a href="list2${pageMaker.makeQuery(idx)}">${idx}</a>
				</c:forEach>
		
				<c:if test="${pageMaker.next && pageMaker.endPage > 0}">
					<a href="list2${pageMaker.makeQuery(pageMaker.endPage +1)}"> » </a>
				</c:if> <br>   
	...(생략)                                           
</body>
</html>

 

1-2. 구현화면

 

 

2. 오라클 11g 이하에서의 페이징 처리 방법은 어떻게 하는가?

2-1. 오라클 11g 이하에서의 페이징 처리방법

: Top-N 쿼리를 수행하기 위해 Inline-View를 이용한다.

SELECT *
FROM (SELECT employee_id, last_name
      FROM hr.employees
      ORDER BY employee_id)
WHERE rownum <= 5;

※. 오라클 12g 부터 적용되는 페이징 처리방법

  1. ROW_NUMBER()를 이용하여 페이징을 적용한다.
    SELECT * 
    FROM (SELECT A.*, ROW_NUMBER() OVER(ORDER BY ID DESC) AS NUM 
    	 FROM OP_SAMPLE A)
    WHERE NUM BETWEEN 999991 AND 1000000;​
  2. 페이지 수를 계산한다.
    SELECT B.* 
    FROM (SELECT CEIL(ROWNUM/10) PAGE--, COUNT(*) OVER() AS TOTAL_COUNT, A.*
    	 FROM (SELECT * 
               FROM OP_SAMPLE 
    		  ORDER BY ID DESC) A) B
    WHERE PAGE = 100000;​
  3. ROWNUM을 이용한다.
    SELECT * 
    FROM (SELECT ROWNUM AS RNUM, Z.* 
          FROM (SELECT * 
                FROM OP_SAMPLE 
                ORDER BY ID DESC) Z
          WHERE ROWNUM <= 1000000)
    WHERE RNUM >= 999991;​
  4. ROWNUM + 인덱스를 이용한다.
    SELECT * 
    FROM (SELECT /*+ INDEX_DESC(Z OP_SAMPLE_PK) */ ROWNUM AS RNUM, Z.* 
          FROM (SELECT * 
                FROM OP_SAMPLE) Z
    	  WHERE ROWNUM <= 1000000)   
    WHERE RNUM >= 999991;​

 

 

3. SQL의 ROWNUM 키워드에 대하여 설명하시오.

3-1. ROWNUM의 정의

: 조회된 순서대로 번호를 매겨 조회할 수 있는 키워드로 기존의 특정 컬럼내 속성값에 의존하여 순번을 매기지 않을 수 있는 장점이 있다. 또한 FROM 및 WHERE 절 처리 후, ROWNUM이 할당되어 해당 절에서 전달되는 각각의 출력 로우(ROW)에 대해 증가하는 특징이 있다.

※. SQL의 처리순서

  • SELECT … 5th
  • FROM … 1st
  • WHERE … 2nd
  • GROUP BY … 3rd
  • HAVING … 4th
  • ORDER BY … 6th