[Spring] 스프링 + MyBatis + MySql 연동
★ 개발환경
- 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()));
}
}