OFFSET을 써야 할까?SQL에서 페이지네이션(pagination) 을 구현할 때 자주 쓰는 방법이 LIMIT과 OFFSET 조합이다.
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}
LIMIT #{limitFrom}, #{limitTake}
👉 따라서, 추후 다른 DB로 옮길 가능성이 있다면 OFFSET 방식을 쓰는 게 안전하다.
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개씩 보여줌
public List<Article> list(int page, int size) {
return mapper.findAll((page - 1) * size, size);
}
(page - 1) * size = offset 계산식ArticleController에서 받은 (int page,int size)를 위 처럼 계산을 하면 (offset, limit)에 들어가기 좋게 변한다.
int page = 3, int size = 10
int offset = 20, int limit = 10.
List<Article> findAll(@Param("offset") int offset, @Param("limit") int limit);
<select id="findAll" resultType="Article">
SELECT * FROM article
ORDER BY id DESC
LIMIT #{limit} OFFSET #{offset}
</select>
LIMIT #{limit} = 가져올 데이터 개수OFFSET #{offset} = 건너뛸 개수사용자가 /article/list?page=3&size=10 요청
Controller: page=3, size=10
Service: (page-1) * size → offset=20
Mapper: findAll(20, 10) 실행
SQL 실행 →
SELECT * FROM article
ORDER BY id DESC
LIMIT 10 OFFSET 20;
→ 21번째부터 10개 데이터 가져옴
Model에 데이터 담아 JSP로 전달
LIMIT ... OFFSET ... → 표준 SQL, DB 호환성 높음 (추천)LIMIT offset, count → MySQL 전용, 이식성 낮음page는 단순히 "사용자가 보고 싶은 페이지 번호"이고,