Spring Boot + MyBatis 게시판 페이지네이션 정리

Jlee7362·2025년 8월 16일

Spring Boot + MyBatis 게시판 페이지네이션 정리

OFFSET을 써야 할까?

SQL에서 페이지네이션(pagination) 을 구현할 때 자주 쓰는 방법이 LIMITOFFSET 조합이다.

MySQL에는 두 가지 방식이 있는데,

-- 표준 SQL 방식 (추천)
SELECT * FROM article 
ORDER BY id DESC 
LIMIT #{limit} OFFSET #{offset};

-- MySQL 전용 방식
SELECT * FROM article 
ORDER BY id DESC 
LIMIT #{limitFrom}, #{limitTake};

차이점

  • LIMIT #{limit} OFFSET #{offset}

    • 표준 SQL 문법
    • MySQL, PostgreSQL, MariaDB, SQLite 등 대부분의 DB에서 지원
    • 다른 DB로 마이그레이션 할 때도 그대로 호환됨
  • LIMIT #{limitFrom}, #{limitTake}

    • MySQL 전용 문법
    • 첫 번째 값은 OFFSET, 두 번째 값은 LIMIT 의미
    • MySQL에서만 동작 → 다른 DB로 옮길 경우 문제가 생길 수 있음

👉 따라서, 추후 다른 DB로 옮길 가능성이 있다면 OFFSET 방식을 쓰는 게 안전하다.


페이지네이션 흐름 (Spring Boot + MyBatis)

1. Controller

public String list(@RequestParam(defaultValue="1") int page,
                   @RequestParam(defaultValue="10") int size,
                   Model model) {
    int total = service.countAll();
    int totalPages = (int)Math.ceil(total / (double)size);

    model.addAttribute("list", service.list(page, size));
    model.addAttribute("page", page);
    model.addAttribute("size", size);
    model.addAttribute("total", total);
    return "article/list";
}
  • page: 사용자가 요청한 페이지 번호 (기본값 1)
  • size: 한 페이지당 보여줄 개수 (기본값 10)

예: /article/list?page=3&size=10 → 3페이지, 한 페이지에 10개씩 보여줌


2. Service

public List<Article> list(int page, int size) {
    return mapper.findAll((page - 1) * size, size);
}
  • (page - 1) * size = offset 계산식
  • page=1 → offset=0 → 1~10번째 데이터
  • page=2 → offset=10 → 11~20번째 데이터

ArticleController에서 받은 (int page,int size)를 위 처럼 계산을 하면 (offset, limit)에 들어가기 좋게 변한다.
int page = 3, int size = 10
int offset = 20, int limit = 10.


3. Mapper 인터페이스

List<Article> findAll(@Param("offset") int offset, @Param("limit") int limit);

4. Mapper XML (SQL)

<select id="findAll" resultType="Article">
    SELECT * FROM article
    ORDER BY id DESC
    LIMIT #{limit} OFFSET #{offset}
</select>
  • LIMIT #{limit} = 가져올 데이터 개수
  • OFFSET #{offset} = 건너뛸 개수

전체 동작 과정

  1. 사용자가 /article/list?page=3&size=10 요청

  2. Controller: page=3, size=10

  3. Service: (page-1) * size → offset=20

  4. Mapper: findAll(20, 10) 실행

  5. SQL 실행 →

    SELECT * FROM article
    ORDER BY id DESC
    LIMIT 10 OFFSET 20;

    → 21번째부터 10개 데이터 가져옴

  6. Model에 데이터 담아 JSP로 전달


정리

  • LIMIT ... OFFSET ... → 표준 SQL, DB 호환성 높음 (추천)
  • LIMIT offset, count → MySQL 전용, 이식성 낮음
  • page는 단순히 "사용자가 보고 싶은 페이지 번호"이고,
    실제 DB 쿼리에서는 offset으로 변환되어 데이터 건너뛰는 기준이 됨

0개의 댓글