사용하는 이유 및 특징:
- 효율적인 데이터 로딩:
- 대용량 데이터를 모두 한번에 로딩하는 것은 시스템에 부하를 줄 수 있기 때문에 페이징 처리를 통해 필요한 만큼의 데이터만 로드하여 시스템의 효율성을 높일 수 있다.
- 사용자 경험 향상
- 사용자가 한 페이지에서 너무 많은 정보를 한번에 볼 때, 원하는 데이터를 찾기 어렵고 혼란스러울 수 있다. 페이징 처리를 통해 정보를 구조적으로 제공하면 사용자 경험이 향상된다.
- 네트워크 트래픽 감소
- 한번의 요청으로 모든 데이터를 전송하는 것보다, 필요한 부분만 요청하여 전송하는 것이 네트워크 트래픽을 줄여준다.
- 서버 부하 감소
- 데이터베이스에서 필요한 부분만 쿼리하여 가져오는 것은 서버와 데이터베이스의 부하를 줄여주며, 전체 시스템의 응답 시간을 개선시켜준다.
- 데이터 관리 용이
- 관리자나 사용자가 데이터를 검토하거나 관리할 때, 페이징 처리된 데이터는 보기 편하고 관리하기 쉽다.
- 반응 시간 최적화
- 페이징 처리를 통해 한번에 작은 양의 데이터만 처리하므로, 웹 페이지의 로딩 및 반응 시간이 최적화된다.
- 자원 사용 최적화
- 메모리와 CPU 자원을 효율적으로 사용하여 시스템 성능을 향상시킬 수 있다.
MyBatis:
1. IDE / DataBase / spring initializr 정보
[IDE]
Intelij Community
[DataBase]
MariaDB
[spring initializr 정보]
Project
Gradle - Groovy
Language
Java
Spring Boot
3.15
Package name
com.paging.mybatis
Packaging
Jar
Java
17
Dependencies
Spring Web
Lombok
MariaDB Driver
MyBatis Framework
2. 프로젝트 구조
3. 기본 설정 (application.yml)
server:
port: 8989
spring:
datasource:
driver-class-name: org.mariadb.jdbc.Driver
url: jdbc:mariadb://접속 정보:3306/DB
username: 아이디
password: 비밀번호
mybatis:
type-aliases-package: com.paging.mybatis.model;
mapper-locations: classpath:mapper/*.xml
configuration:
map-underscore-to-camel-case: true
driver-class-name:
사용할 JDBC 드라이버의 클래스 이름을 지정한다. 여기서는 MariaDB의 JDBC 드라이버인 org.mariadb.jdbc.Driver를 사용한다.
url:
데이터베이스에 접속하기 위한 URL을 지정한다. jdbc:mariadb://접속 정보:3306/DB와 같이 접속 정보와 포트, 데이터베이스 이름을 입력한다.
username:
데이터베이스에 접속할 사용자의 아이디를 지정한다.
password:
데이터베이스에 접속할 사용자의 비밀번호를 지정한다.
type-aliases-package:
MyBatis의 Type Aliases를 사용하기 위해 지정된 패키지를 설정한다. 여기서는 com.paging.mybatis.model 패키지를 지정하여 해당 패키지 내에 있는 클래스들을 Type Aliases로 사용할 수 있도록 한다.
mapper-locations:
MyBatis의 매퍼 파일 위치를 설정한다. classpath:mapper/*.xml와 같이 클래스패스 상의 mapper 폴더 내에 있는 모든 XML 파일을 매퍼로 인식한다.
configuration.map-underscore-to-camel-case:
MyBatis가 데이터베이스의 컬럼명을 자바의 카멜케이스 형식에 맞게 매핑할지 여부를 설정한다. true로 설정하면 데이터베이스 컬럼명의 언더스코어(_)를 자바의 카멜케이스로 변환하여 매핑한다.
4. 소스 코드
PageInfo (java)
package com.paging.mybatis.common.paging;
import java.io.Serializable;
import java.util.List;
public class PageInfo<T> implements Serializable {
private static final long serialVersionUID = 1L;
private final int pageIndex;
private final int pageSize;
private final int totalCount;
private final List<T> data;
public PageInfo(int pageIndex, int pageSize, int totalCount, List<T> data) {
this.pageIndex = pageIndex;
this.pageSize = pageSize;
this.totalCount = totalCount;
this.data = data;
}
public int getPageIndex() {
return pageIndex;
}
public int getPageSize() {
return pageSize;
}
public int getTotalCount() {
return totalCount;
}
public int getTotalPage() {
return (int) Math.ceil((double) totalCount / pageSize);
}
public List<T> getData() {
return data;
}
}
BoardController (java)
package com.paging.mybatis.controller;
import com.paging.mybatis.service.BoardService;
import com.paging.mybatis.model.Board;
import com.paging.mybatis.common.paging.PageInfo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class BoardController {
@Autowired
private BoardService boardService;
@GetMapping("/boards")
public PageInfo<Board> getBoards(
@RequestParam(defaultValue = "1") int pageIndex,
@RequestParam(defaultValue = "10") int pageSize) {
return boardService.getBoards(pageIndex, pageSize);
}
}
BoardMapper (interface)
package com.paging.mybatis.mapper;
import com.paging.mybatis.model.Board;
import org.apache.ibatis.annotations.Mapper;
import java.util.List;
@Mapper
public interface BoardMapper {
int getTotalCount();
List<Board> findBoards(int offset, int limit);
}
Board (java)
package com.paging.mybatis.model;
import lombok.Data;
import java.time.LocalDateTime;
@Data
public class Board {
private Long id; // 기본 키
private String title; // 제목
private String content; // 내용
private String createdBy; // 생성자
private LocalDateTime createdAt; // 생성 일자
}
BoardService (java)
package com.paging.mybatis.service;
import com.paging.mybatis.model.Board;
import com.paging.mybatis.mapper.BoardMapper;
import com.paging.mybatis.common.paging.PageInfo;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class BoardService {
private final BoardMapper boardMapper;
public BoardService(BoardMapper boardMapper) {
this.boardMapper = boardMapper;
}
public PageInfo<Board> getBoards(int pageIndex, int pageSize) {
int totalCount = boardMapper.getTotalCount();
List<Board> boards = boardMapper.findBoards((pageIndex - 1) * pageSize, pageSize);
return new PageInfo<>(pageIndex, pageSize, totalCount, boards);
}
}
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="com.paging.mybatis.mapper.BoardMapper">
<select id="getTotalCount" resultType="int">
SELECT COUNT(*) FROM board
</select>
<select id="findBoards" resultType="Board">
SELECT * FROM board LIMIT #{limit} OFFSET #{offset}
</select>
</mapper>
5. 실행 결과 (JSON)
// 20231104022159
// http://localhost:8989/boards
{
"pageIndex": 1,
"pageSize": 10,
"totalCount": 21,
"data": [
{
"id": 1,
"title": "테스트 1",
"content": "안녕하세요",
"createdBy": "StudyMemo",
"createdAt": "2023-11-02T17:15:43"
},
{
"id": 2,
"title": "테스트 2",
"content": "안녕하세요",
"createdBy": "StudyMemo",
"createdAt": "2023-11-02T17:15:43"
},
{
"id": 3,
"title": "테스트 3",
"content": "안녕하세요",
"createdBy": "StudyMemo",
"createdAt": "2023-11-02T17:15:43"
},
{
"id": 4,
"title": "테스트 4",
"content": "안녕하세요",
"createdBy": "StudyMemo",
"createdAt": "2023-11-02T17:15:43"
},
{
"id": 5,
"title": "테스트 5",
"content": "안녕하세요",
"createdBy": "StudyMemo",
"createdAt": "2023-11-02T17:15:43"
},
{
"id": 6,
"title": "테스트 6",
"content": "안녕하세요",
"createdBy": "StudyMemo",
"createdAt": "2023-11-02T17:15:43"
},
{
"id": 7,
"title": "테스트 7",
"content": "안녕하세요",
"createdBy": "StudyMemo",
"createdAt": "2023-11-02T17:15:43"
},
{
"id": 8,
"title": "테스트 8",
"content": "안녕하세요",
"createdBy": "StudyMemo",
"createdAt": "2023-11-02T17:15:43"
},
{
"id": 9,
"title": "테스트 9",
"content": "안녕하세요",
"createdBy": "StudyMemo",
"createdAt": "2023-11-02T17:15:43"
},
{
"id": 10,
"title": "테스트 10",
"content": "안녕하세요",
"createdBy": "StudyMemo",
"createdAt": "2023-11-02T17:15:43"
}
],
"totalPage": 3
}
JPA:
1. IDE / DataBase / spring initializr 정보
[IDE]
Intelij Community
[DataBase]
MariaDB
[spring initializr 정보]
Project
Gradle - Groovy
Language
Java
Spring Boot
3.15
Package name
com.paging.jpa
Packaging
Jar
Java
17
Dependencies
Spring Web
Lombok
MariaDB Driver
Spring Data JPA
2. 프로젝트 구조
3. 기본 설정 (application.yml)
server:
port: 9898
spring:
datasource:
driver-class-name: org.mariadb.jdbc.Driver
url: jdbc:mariadb://접속정보:3306/DB
username: 아이디
password: 비밀번호
jpa:
hibernate:
ddl-auto: update
show-sql: true
properties:
hibernate:
format_sql: true
driver-class-name:
사용할 JDBC 드라이버의 클래스 이름을 지정한다. 여기서는 MariaDB의 JDBC 드라이버인 org.mariadb.jdbc.Driver를 사용한다.
url:
데이터베이스에 접속하기 위한 URL을 지정한다. jdbc:mariadb://접속 정보:3306/DB와 같이 접속 정보와 포트, 데이터베이스 이름을 입력한다.
username:
데이터베이스에 접속할 사용자의 아이디를 지정한다.
password:
데이터베이스에 접속할 사용자의 비밀번호를 지정한다.
hibernate.ddl-auto:
데이터베이스의 스키마를 자동으로 생성 및 갱신하는 방식을 설정한다.
update로 설정하면 애플리케이션 실행 시 엔티티 클래스에 변경이 있으면 해당 변경을 데이터베이스에 반영한다.
show-sql:
Hibernate가 실행하는 SQL 쿼리를 콘솔에 출력할지 여부를 설정한다.
true로 설정하면 실행되는 SQL 쿼리를 확인할 수 있다.
hibernate.format_sql:
출력되는 SQL 쿼리를 읽기 쉬운 형식으로 포맷팅할지 여부를 설정한다.
true로 설정하면 쿼리를 읽기 쉬운 형태로 출력다.
4. 소스 코드
BoardController (java)
package com.paging.jpa.controller;
import com.paging.jpa.model.Board;
import com.paging.jpa.service.BoardService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/boards")
public class BoardController {
@Autowired
private BoardService boardService;
@GetMapping
public Page<Board> list(@RequestParam(defaultValue = "0") int page,
@RequestParam(defaultValue = "10") int size) {
return boardService.getBoards(page, size);
}
}
Board (java)
package com.paging.jpa.model;
import jakarta.persistence.*;
import lombok.Data;
import java.time.LocalDateTime;
@Data
@Entity
@Table(name="board")
public class Board {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id; // 기본 키
@Column(name = "title")
private String title; // 제목
@Column(name = "content")
private String content; // 내용
@Column(name = "createdBy")
private String createdBy; // 생성자
@Column(name = "createdAt")
private LocalDateTime createdAt; // 생성 일자
}
BoardRepository (java)
package com.paging.jpa.repository;
import com.paging.jpa.model.Board;
import org.springframework.data.jpa.repository.JpaRepository;
public interface BoardRepository extends JpaRepository<Board, Long> {
// 기본 CRUD 메서드와 페이징 처리를 위한 메서드 자동으로 제공
}
BoardService (java)
package com.paging.jpa.service;
import com.paging.jpa.model.Board;
import com.paging.jpa.repository.BoardRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.stereotype.Service;
@Service
public class BoardService {
@Autowired
private BoardRepository boardRepository;
public Page<Board> getBoards(int page, int size) {
return boardRepository.findAll(PageRequest.of(page, size));
}
}
5. 실행 결과 (JSON)
// 20231104022306
// http://localhost:9898/boards
{
"content": [
{
"id": 1,
"title": "테스트 1",
"content": "안녕하세요",
"createdBy": "StudyMemo",
"createdAt": "2023-11-02T17:15:43"
},
{
"id": 2,
"title": "테스트 2",
"content": "안녕하세요",
"createdBy": "StudyMemo",
"createdAt": "2023-11-02T17:15:43"
},
{
"id": 3,
"title": "테스트 3",
"content": "안녕하세요",
"createdBy": "StudyMemo",
"createdAt": "2023-11-02T17:15:43"
},
{
"id": 4,
"title": "테스트 4",
"content": "안녕하세요",
"createdBy": "StudyMemo",
"createdAt": "2023-11-02T17:15:43"
},
{
"id": 5,
"title": "테스트 5",
"content": "안녕하세요",
"createdBy": "StudyMemo",
"createdAt": "2023-11-02T17:15:43"
},
{
"id": 6,
"title": "테스트 6",
"content": "안녕하세요",
"createdBy": "StudyMemo",
"createdAt": "2023-11-02T17:15:43"
},
{
"id": 7,
"title": "테스트 7",
"content": "안녕하세요",
"createdBy": "StudyMemo",
"createdAt": "2023-11-02T17:15:43"
},
{
"id": 8,
"title": "테스트 8",
"content": "안녕하세요",
"createdBy": "StudyMemo",
"createdAt": "2023-11-02T17:15:43"
},
{
"id": 9,
"title": "테스트 9",
"content": "안녕하세요",
"createdBy": "StudyMemo",
"createdAt": "2023-11-02T17:15:43"
},
{
"id": 10,
"title": "테스트 10",
"content": "안녕하세요",
"createdBy": "StudyMemo",
"createdAt": "2023-11-02T17:15:43"
}
],
"pageable": {
"pageNumber": 0,
"pageSize": 10,
"sort": {
"empty": true,
"unsorted": true,
"sorted": false
},
"offset": 0,
"paged": true,
"unpaged": false
},
"last": false,
"totalPages": 3,
"totalElements": 21,
"size": 10,
"number": 0,
"sort": {
"empty": true,
"unsorted": true,
"sorted": false
},
"first": true,
"numberOfElements": 10,
"empty": false
}
'Spring' 카테고리의 다른 글
Spring Data JPA의 페이징 처리 이해하기: 'Pageable'과 'Page' (0) | 2023.11.06 |
---|---|
API 문서 자동화: Swagger와 Spring REST Docs의 특징과 장단점 (0) | 2023.10.13 |
[Spring] VO에서 null 값을 없애고 싶다면? (@JsonInclude) (0) | 2022.07.13 |
[Spring] JPA vs MyBatis 정리 (특징, 장점, 단점 등) (0) | 2022.06.24 |
[Spring] 프로퍼티(properties) 파일을 이용한 값 설정 (0) | 2022.06.16 |