Back-end/Spring

[Spring] 스프링 + MyBatis + MySql 연동

영벨롭 2023. 8. 6. 15:43

★ 개발환경

  • Spring Framework
  • MySql
  • MyBatis
  • Docker

운영체제는 MAC 을 기준으로 포스팅하겠습니다.

 


★ Docker

 저는 MySql 을 실행하기 위해 도커를 사용했습니다. 도커 설치에 대한 자료는 다른 레퍼런스를 참고해주세요.

 

 도커 설치 후 다음 명령어를 터미널에 입력하여 설치가 완료되었는지 확인합니다. 

docker -v

 

 도커로 MySql 을 실행하기 위해 도커 저장소에서 MySql 이미지를 가져와야 합니다. 다음 명령어를 통해 이미지를 가져옵니다.

docker pull mysql

 도커로 이미지를 잘 가져왔는지 확인합니다. 

docker images

 

 이제 Docker MySql 컨테이너를 생성하고 실행합니다. 

docker run --name <컨테이너이름> -e MYSQL_ROOT_PASSWORD=<비밀번호> -d -p 3306:3306 mysql:latest

 


★ MySql Workbench

 우선 MySql workbench 를 설치합니다. 

 

 설치가 완료되면 워크벤치를 실행 후, MySql Connections 옆 + 버튼을 클릭하여 커넥션을 추가합니다.

 

 저는 커넥션 이름을 localhost-root 로 지정 후, 다음과 같이 커넥션을 생성하였습니다. 

 

 생성 후, 해당 커넥션으로 이동하여 Schemas 탭에서 demo_schema 라는 이름의 스키마를 생성합니다.

 

 이제 다시 Administration 탭으로 돌아와 'Users and Privileges' 을 클릭하여 계정을 생성합니다. 

 이때 생성한 계정의 이름과 비밀번호를 기억해주세요!

 

 계정을 생성하셨다면 해당 계정의 Schema Privileges 탭을 클릭 후, Add Entry 버튼을 통해 계정에 이미 만들어 두었던 demo_schema 스키마를 등록해줍니다.

 

 이제 다시 홈으로 돌아와 새로운 커넥션을 생성합니다. 생성한 계정 이름(Username), 비밀번호(Password), Default Schema 를 입력 합니다. 

 

 해당 커넥션으로 이동하여 연결이 잘 되었는지 확인해봅시다!

 확인용으로 select 1 from dual; 선어문을 작성하여 실행 후 다음과 같이 나타난다면 성공입니다.

 

 id, title, content, writer 를 칼럼으로 갖는 post 테이블을 생성합니다.

 기본적으로 모든 칼럼을 Not NULL 로 설정해주시고 기본키인 id 는 Primary Key 와 Auto Increment 를 설정해주세요.

 


★ Spring 프로젝트 생성

https://start.spring.io/ 에서 Spring 프로젝트를 생성합니다. 

 

Dependecies

  • Spring Web
  • MyBatis Framework
  • MySQL Driver

// build.gradle

plugins {
	id 'java'
	id 'org.springframework.boot' version '2.7.14'
	id 'io.spring.dependency-management' version '1.0.15.RELEASE'
}

group = 'com.dev'
version = '0.0.1-SNAPSHOT'

java {
	sourceCompatibility = '11'
}

repositories {
	mavenCentral()
}

dependencies {
	implementation 'org.springframework.boot:spring-boot-starter-web'
	implementation 'org.mybatis.spring.boot:mybatis-spring-boot-starter:2.3.1'
	runtimeOnly 'com.mysql:mysql-connector-j'
	testImplementation 'org.springframework.boot:spring-boot-starter-test'
	testImplementation 'org.mybatis.spring.boot:mybatis-spring-boot-starter-test:2.3.1'
}

tasks.named('test') {
	useJUnitPlatform()
}

 


★ application.yml

  /src/main/resources/ 위치에서 편의를 위해 application.properties 대신 application.yml 파일로 변경하여 MyBatis 를 사용하기 위한 설정을 합니다.

spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://127.0.0.1:3306/demo_schema
    username: demo_user
    password: #계정 비밀번호

mybatis:
  mapper-locations: "classpath:mybatis/mappers/*.xml"
  configuration:
    map-underscore-to-camel-case: true
  • username: 계정 이름
  • password: 해당 계정 비밀번호
  • mapper-locations: Mybatis mapper 파일의 위치
  • map-underscore-to-camel-case: 대부분의 데이터베이스는 스네이크 케이스(snake_case) 를 사용하고 자바는 카멜 케이스(camelCase) 를 사용하는데, 이 옵션을 설정하게 되면 MyBatis 가 스네이크 케이스를 카멜 케이스로 변환해줍니다.

★ 패키지 및 파일 생성

이번 프로젝트에서 사용할 패키지와 파일들입니다. 


★ PostDto

 앞서 정의한 post 테이블의 칼럼 데이터에 맞게 dto 를 정의합니다. 

 기본적인 Getter, Setter 도 함께 작성합니다.

package com.dev.demomybatis.dto;

public class PostDto {
    private int id;
    private String title;
    private String content;
    private String writer;

    public PostDto() {

    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public String getContent() {
        return content;
    }

    public void setContent(String content) {
        this.content = content;
    }

    public String getWriter() {
        return writer;
    }

    public void setWriter(String writer) {
        this.writer = writer;
    }

    @Override
    public String toString() {
        return "PostDto{" +
                "id=" + id +
                ", title='" + title + '\'' +
                ", content='" + content + '\'' +
                ", writer='" + writer + '\'' +
                '}';
    }
}

 


★ PostMapper

 XML 파일의 SQL 선언문과 연결될 메소드를 정의하는 인터페이스를 생성합니다.

 간단한 CRUD 만 구현하겠습니다.

package com.dev.demomybatis.mapper;

import com.dev.demomybatis.dto.PostDto;

import java.util.List;

public interface PostMapper {
    int createPost(PostDto dto); // 게시글 생성
    List<PostDto> readPostAll(); // 게시글 목록 조회
    PostDto readPost(int id); // 게시글 조회
    int updatePost(PostDto dto); // 게시글 수정
    int deletePost(int id); // 게시글 삭제
}

★ PostDao

 PostMapper 에서 선언한 메소드를 구현합니다.

package com.dev.demomybatis.dao;

import com.dev.demomybatis.dto.PostDto;
import com.dev.demomybatis.mapper.PostMapper;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;

import java.util.List;

@Repository
public class PostDao {
    private final SqlSessionFactory sqlSessionFactory;

    public PostDao(
            @Autowired SqlSessionFactory sqlSessionFactory
    ) {
        this.sqlSessionFactory = sqlSessionFactory;
    }

    public int createPost(PostDto dto) {
        try(SqlSession session = sqlSessionFactory.openSession()) {
            PostMapper mapper = session.getMapper(PostMapper.class);
            return mapper.createPost(dto);
        }
    }

    public List<PostDto> readPostAll() {
        try(SqlSession session = sqlSessionFactory.openSession()) {
            PostMapper mapper = session.getMapper(PostMapper.class);
            return mapper.readPostAll();
        }
    }

    public PostDto readPost(int id) {
        try(SqlSession session = sqlSessionFactory.openSession()) {
            PostMapper mapper = session.getMapper(PostMapper.class);
            return mapper.readPost(id);
        }
    }

    public int updatePost(PostDto dto) {
        try(SqlSession session = sqlSessionFactory.openSession()) {
            PostMapper mapper = session.getMapper(PostMapper.class);
            return mapper.updatePost(dto);
        }
    }

    public int deletePost(int id) {
        try(SqlSession session = sqlSessionFactory.openSession()) {
            PostMapper mapper = session.getMapper(PostMapper.class);
            return mapper.deletePost(id);
        }
    }
}

★ post-mapper.xml

 앞서 application.yml 에서 mapper-locations: "classpath:mybatis/mappers/*.xml" 설정을 해주었는데, 이는 MyBatis 가 어플리케이션 실행 시 이 위치에 있는 모든 xml 파일을 읽어들여 미리 정의해 놓은 메소드에 연결해줍니다.

 /src/main/resources/mybatis/mappers/ 위치에 post-mapper.xml 파일을 생성하여 SQL 선언문을 작성합니다.

<?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.dev.demomybatis.mapper.PostMapper">
    <insert
            id="createPost"
            parameterType="com.dev.demomybatis.dto.PostDto"
    >
        insert into post(title, content, writer)
        values(#{title}, #{content}, #{writer})
    </insert>
    <select
            id="readPostAll"
            resultType="com.dev.demomybatis.dto.PostDto"
    >
        select * from post
    </select>
    <select
            id="readPost"
            parameterType="int"
            resultType="com.dev.demomybatis.dto.PostDto"
    >
        select * from post where id = ${id}
    </select>
    <update id="updatePost" parameterType="com.dev.demomybatis.dto.PostDto">
        update post
        set
            title = #{title},
            content = #{content},
            writer = #{writer}
        where id = ${id}
    </update>
    <delete id="deletePost" parameterType="int">
        delete from post where id = ${id}
    </delete>
</mapper>

 


★ 테스트

package com.dev.demomybatis;

import com.dev.demomybatis.dao.PostDao;
import com.dev.demomybatis.dto.PostDto;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.List;

@Component
public class TestComponent {
    private final PostDao postDao;

    public TestComponent(
            @Autowired PostDao postDao
    ) {
        this.postDao = postDao;

        PostDto newPost = new PostDto();
        newPost.setTitle("From Mybatis");
        newPost.setContent("Hello Database!");
        newPost.setWriter("Test user");
        this.postDao.createPost(newPost);

        List<PostDto> postDtoList = this.postDao.readPostAll();
        System.out.println(postDtoList.get(postDtoList.size() - 1));

        PostDto firstPost = postDtoList.get(0);
        firstPost.setContent("content updated from mybatis!");
        this.postDao.updatePost(firstPost);

        System.out.println(this.postDao.readPost(firstPost.getId()));
    }
}

 

MySql workbench

 

반응형