Experience/LG CNS AM Inspire Camp 1기

[LG CNS AM Inspire Camp] 15. 스프링 부트와 MyBatis를 활용한 데이터베이스 연동

chillmyh 2025. 2. 10. 19:12

1. 스프링 부트(Spring Boot)

스프링 부트(Spring Boot)는 스프링 프레임워크를 기반으로 한 간편한 애플리케이션 개발을 위한 프레임워크이다. 개발자가 설정을 최소화하고 빠르게 개발을 진행할 수 있도록 다양한 자동 설정을 제공한다.

1.1. 주요 특징

  • 내장 웹 서버 제공: Tomcat, Jetty, Undertow 등의 웹 서버를 내장하여 별도의 설정 없이 실행 가능
  • 자동 설정(Auto Configuration): 설정을 최소화하여 빠른 개발 가능
  • 의존성 관리: 스타터(Starter) 의존성을 활용하여 필요한 기능을 손쉽게 추가 가능
  • Spring Boot CLI 지원: CLI(Command Line Interface)를 활용한 빠른 애플리케이션 실행

1.2. 스프링 부트 프로젝트 생성 및 실행

프로젝트 생성

스프링 부트 프로젝트는 Spring Initializr(https://start.spring.io/) 를 이용하여 쉽게 생성할 수 있다.

InteliiJ 유료버전을 사용하면 IDE 내에서 생성이 가능하다.

 

추가한 의존성 :

  • Spring Boot Starter Web
  • Spring Boot Starter Data JPA
  • MyBatis Spring Boot Starter
  • MySQL Driver

실행 방법

@SpringBootApplication
public class SampleApplication {
    public static void main(String[] args) {
        SpringApplication.run(SampleApplication.class, args);
    }
}

위와 같이 SpringApplication.run()을 실행하면 스프링 부트 애플리케이션이 자동으로 실행된다.

2. MyBatis와 데이터베이스 연동

2.1. MyBatis란?

MyBatis는 자바 애플리케이션에서 관계형 데이터베이스와 상호작용할 수 있도록 돕는 퍼시스턴스 프레임워크이다. SQL을 명확하게 제어하면서도 매핑을 자동화할 수 있도록 도와준다.

MyBatis의 특징

  • SQL을 XML 또는 어노테이션으로 관리할 수 있어 SQL 튜닝이 용이함
  • JDBC보다 간결한 코드 작성 가능
  • ORM(Object-Relational Mapping) 프레임워크보다 유연성이 높음

2.2. MyBatis 설정

데이터베이스 연결 설정 (application.properties)

spring.datasource.url=jdbc:mysql://localhost:3306/springbootdb
spring.datasource.username=root
spring.datasource.password=root
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver

위 설정을 통해 MySQL 데이터베이스와 연결할 수 있다.

MyBatis 설정 (DatabaseConfiguration.java)

@Configuration
@MapperScan("com.example.demo.mapper")
public class DatabaseConfiguration {
    @Bean
    @ConfigurationProperties(prefix = "spring.datasource.hikari")
    public HikariConfig hikariConfig() {
        return new HikariConfig();
    }

    @Bean
    public DataSource dataSource() {
        return new HikariDataSource(hikariConfig());
    }

    @Bean
    public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception {
        SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean();
        sessionFactory.setDataSource(dataSource);
        return sessionFactory.getObject();
    }

    @Bean
    public SqlSessionTemplate sqlSessionTemplate(SqlSessionFactory sqlSessionFactory) {
        return new SqlSessionTemplate(sqlSessionFactory);
    }
}

위 설정을 통해 HikariCP를 이용한 커넥션 풀을 설정하고, MyBatis의 SqlSessionFactory를 생성한다.

2.3. MyBatis를 활용한 CRUD 구현

1️⃣ 테이블 생성 (t_board)

CREATE TABLE t_board (
    board_idx INT(11) NOT NULL AUTO_INCREMENT,
    title VARCHAR(300) NOT NULL,
    contents TEXT NOT NULL,
    hit_cnt SMALLINT(10) NOT NULL DEFAULT 0,
    created_dt DATETIME NOT NULL,
    created_id VARCHAR(300) NOT NULL,
    PRIMARY KEY (board_idx)
);

위 테이블은 게시판 기능을 위한 기본 테이블이며, 제목, 내용, 조회수 등의 컬럼을 포함한다.

2️⃣ DTO(Data Transfer Object) 생성

@Data
public class BoardDto {
    private int boardIdx;
    private String title;
    private String contents;
    private int hitCnt;
    private String createdDt;
    private String createdId;
}

DTO는 데이터베이스에서 가져온 데이터를 Java 객체로 변환하는 역할을 한다.

3️⃣ DAO(Data Access Object) 인터페이스

@Mapper
public interface BoardMapper {
    @Insert("INSERT INTO t_board (title, contents, hit_cnt, created_dt, created_id) VALUES (#{title}, #{contents}, #{hitCnt}, NOW(), #{createdId})")
    void insertBoard(BoardDto board);

    @Select("SELECT * FROM t_board WHERE board_idx = #{boardIdx}")
    BoardDto selectBoard(int boardIdx);
}

4️⃣ 서비스(Service) 클래스 구현

@Service
public class BoardService {
    @Autowired
    private BoardMapper boardMapper;

    public void addBoard(BoardDto board) {
        boardMapper.insertBoard(board);
    }

    public BoardDto getBoard(int boardIdx) {
        return boardMapper.selectBoard(boardIdx);
    }
}

5️⃣ 컨트롤러(Controller) 구현

@RestController
@RequestMapping("/board")
public class BoardController {
    @Autowired
    private BoardService boardService;

    @PostMapping("/add")
    public void addBoard(@RequestBody BoardDto board) {
        boardService.addBoard(board);
    }

    @GetMapping("/{boardIdx}")
    public BoardDto getBoard(@PathVariable int boardIdx) {
        return boardService.getBoard(boardIdx);
    }
}

3. DAL과 DAO, DTO, VO

DAL (Data Access Layer, 데이터 접근 계층) 은 데이터베이스와 애플리케이션 간의 상호작용을 담당하는 계층이다.

DAO, DTO, VO는 DAL의 일부로 간주될 수 있지만, DAL 전체를 의미하지는 않는다.

보통 DAO와 DataSource를 포함하여 DB와 관련된 모든 처리를 담당하는 계층을 DAL이라고 한다.

DAL의 역할

  • DAO를 이용해 데이터를 가져오거나 저장한다.
  • DTO를 사용해 데이터를 계층 간 전달한다.
  • VO를 사용해 데이터를 불변 객체로 관리한다.
  • DataSource를 사용해 데이터베이스와의 연결을 관리한다.

 

3.1 DAO (Data Access Object)

  • DAO는 데이터베이스와 직접적으로 상호작용하는 객체.
  • 데이터베이스에서 데이터를 가져오거나 저장하는 역할을 한다.
  • SQL을 사용하여 CRUD(Create, Read, Update, Delete) 연산을 수행한다.
  • DAO 패턴을 사용하면 비즈니스 로직과 데이터 접근을 분리할 수 있다.
  • DAO의 특징
    • JDBC, JPA, MyBatis 등을 사용하여 DB와 상호작용한다.
    • 보통 인터페이스와 구현 클래스를 사용하여 설계된다.

DAO 예제 (JDBC Template 사용)

@Repository
public class UserDAO {
    private final JdbcTemplate jdbcTemplate;

    @Autowired
    public UserDAO(JdbcTemplate jdbcTemplate) {
        this.jdbcTemplate = jdbcTemplate;
    }

    public List<UserDTO> getAllUsers() {
        String sql = "SELECT id, name, email FROM users";
        return jdbcTemplate.query(sql, (rs, rowNum) -> new UserDTO(
                rs.getInt("id"),
                rs.getString("name"),
                rs.getString("email")
        ));
    }
}
  • UserDAO는 데이터베이스에서 사용자 정보를 가져오는 역할을 한다.

3.2 DTO (Data Transfer Object)

  • DTO는 계층 간(예: Controller ↔ Service ↔ DAO) 데이터를 주고받는 객체.
  • 데이터의 이동을 위해 만들어지며, 비즈니스 로직이 포함되지 않는다.
  • DTO는 데이터베이스에서 가져온 데이터를 클라이언트(프론트엔드) 또는 서비스 계층으로 전달할 때 사용돼.
  • DTO는 일반적으로 Getter, Setter, 생성자만 포함하는 단순한 객체다.

DTO 예제

public class UserDTO {
    private int id;
    private String name;
    private String email;

    public UserDTO(int id, String name, String email) {
        this.id = id;
        this.name = name;
        this.email = email;
    }

    // Getter & Setter
    public int getId() { return id; }
    public void setId(int id) { this.id = id; }
    
    public String getName() { return name; }
    public void setName(String name) { this.name = name; }

    public String getEmail() { return email; }
    public void setEmail(String email) { this.email = email; }
}
  • DTO는 데이터를 보존하는 역할만 담당하며, 별도의 로직이 없다.

3.3 VO (Value Object)

  • VO는 불변(Immutable) 객체로, 생성 후 값이 변하지 않는다.
  • 값 객체(Value Object)라고 불리며, 동일성(Identity)보다 값 자체를 중요하게 다루는 객체.
  • Setter가 없으며, 값이 변경될 경우 새로운 객체를 생성해야 한다.
  • equals()와 hashCode()를 재정의하여 객체의 값 비교를 수행한다.
  • VO는 도메인 모델에서 많이 사용되며, JPA의 @Embeddable과 함께 활용될 수 있다.

VO 예제

public class UserVO {
    private final int id;
    private final String name;
    private final String email;

    public UserVO(int id, String name, String email) {
        this.id = id;
        this.name = name;
        this.email = email;
    }

    public int getId() { return id; }
    public String getName() { return name; }
    public String getEmail() { return email; }

    @Override
    public boolean equals(Object obj) {
        if (this == obj) return true;
        if (obj == null || getClass() != obj.getClass()) return false;
        UserVO userVO = (UserVO) obj;
        return id == userVO.id && name.equals(userVO.name) && email.equals(userVO.email);
    }

    @Override
    public int hashCode() {
        return Objects.hash(id, name, email);
    }
}
  • VO는 불변성을 유지하여 데이터의 신뢰성을 높이는 데 도움을 준다.

3.4 DAO, DTO, VO 차이점 정리

구분 역할 특징 예제
DAO (Data Access Object) DB와 직접 상호작용 SQL을 사용하여 CRUD 구현 UserDAO
DTO (Data Transfer Object) 계층 간 데이터 전달 데이터 이동만 담당, 비즈니스 로직 없음 UserDTO
VO (Value Object) 불변 데이터 객체 값이 변하지 않음, equals()와 hashCode() 재정의 UserVO

4. 마무리

이번 강의를 통해 스프링 부트와 MyBatis를 활용한 데이터베이스 연동을 학습했다. 특히, HikariCP를 이용한 커넥션 풀 설정, MyBatis 매퍼 인터페이스 활용, DAO 패턴을 적용한 CRUD 구현 방법 등을 배울 수 있었다.

스프링 부트와 MyBatis를 활용하면 SQL을 직접 제어하면서도 객체 매핑이 가능하기 때문에, 데이터베이스 중심의 애플리케이션 개발에 유용하게 활용할 수 있다.

JPA를 주로 사용하다가 MyBatis를 사용해보니까 역체감이 나긴하는데.. 좋은 것 같다.

 


이 글은 LG CNS AM Inspire Camp 1기 진행 중 Obsidian에 정리해뒀던 글을 블로그에 옮긴 글입니다.