💡MyBatis란?

자바 기반의 데이터베이스를 쉽게 다룰 수 있도록 도와주는 오픈 소스 ORM(Object-Relation Mapping) 프레임워크
- SQL, 저장 프로시저 및 고급 매핑 기능 지원
- XML 파일이나 애노테이션을 사용하여 SQL 쿼리를 작성하고, 자바 객체와 데이터베이스의 테이블 간의 매핑 처리
✔️ Mapper 예시코드
@Mapper
public interface MemberMapper {
//mapper의 id와 맞아야함.
int insert(MemberVO memberVO); //<insert id="insert" ~~>
int update(MemberVO memberVO);
int delete(String id);
MemberVO one(String id); // <select id="one" ~~>
List<MemberVO> all();
int login(MemberVO memberVO);
List<MemberVO> find(String word);
}
✔️ MyBatis vs JPA
| 항목 | MyBatis | JPA |
| 접근 방식 | SQL 직접 작성 | 객체-관계 매핑(ORM) |
| 설정 방식 | XML 매핑 파일, 애노테이션 | 애노테이션, XML 설정 |
| 유연성 | 높음 | 중간 |
| 자동화 수준 | 낮음 | 높음 |
| 쿼리 언어 | SQL | JPQL |
| 데이터베이스 의존성 | 높음 | 낮음 |
| 성능 최적화 | 가능 (SQL 직접 작성) | 제한적 (ORM 추상화) |
| 학습 곡선 | 중간 | 높음 |
| 디버깅 및 유지보수 | 쉬움 | 어려움 |
💡MyBatis 실습
오늘 실습해 볼 파일 구조 살펴보기! (MVC2 구조)


✔️Model
| 파일명 | 설명 |
| MemberVO.java | 회원 정보를 담는 Value Object 클래스 Lombok 애노테이션을 사용하여 getter, setter, 생성자를 자동 생성 |
| MemberDAO.java | 메모리 내 데이터베이스 역할을 하며 회원 정보의 CRUD 작업을 담당 |
✔️ View
| 파일명 | 설명 |
| member.jsp | 회원 정보를 입력받는 폼을 제공 |
| all_result.jsp | 모든 회원 정보를 테이블 형식으로 출력 |
| insert_result.jsp | 회원 추가 결과를 출력 |
| update_result.jsp | 회원 수정 결과를 출력 |
| delete_result.jsp | 회원 삭제 결과를 출력 |
| one_result.jsp | 단일 회원 정보를 출력 |
✔️Control
| 파일명 | 설명 |
| MemberController.java | 회원 정보와 관련된 요청을 처리 |
| RootController.java | 루트 경로와 관련된 요청을 처리 |
| BoardController.java | 게시판 관련 요청을 처리 |
✔️ Service
| 파일명 | 설명 |
| MemberService.java | 비즈니스 로직을 처리하며 DAO를 통해 데이터베이스 작업을 수행 |
✔️Config
| 파일명 | 설명 |
| AppConfig.java | 애플리케이션의 기본 설정을 담당 |
| WebConfig.java | Spring MVC 설정을 담당하며, 뷰 리졸버를 설정 |
| WebAppInitializer.java | 서블릿 컨테이너를 초기화 |
💡myBatis 설정하기

| 설명 파일 | 이름 | 구분 | 패키지 및 경로 |
| 데이터베이스 접근 객체 (DAO) | MemberDAO | Java 파일 | com.multi.spring3.dao |
| MyBatis 매퍼 인터페이스 | MemberMapper | Java 파일 | com.multi.spring3.mapper |
| MyBatis 매퍼 XML 설정 파일 | memberMapper.xml | XML 파일 | resources.mapper |
| MyBatis 설정 파일 | mybatis-config.xml | XML 파일 | resources |
💡Data 준비
create database shop2;
use shop2;
CREATE TABLE `member` (
`id` varchar(45) NOT NULL,
`pw` varchar(45) NOT NULL,
`name` varchar(45) DEFAULT NULL,
`tel` varchar(45) DEFAULT NULL,
PRIMARY KEY (`id`)
);
desc member;
CREATE TABLE `board` (
`no` int NOT NULL AUTO_INCREMENT,
`title` varchar(45) NOT NULL,
`content` varchar(45) NOT NULL,
`writer` varchar(45) NOT NULL,
PRIMARY KEY (`no`)
);
desc board;
💡config 폴더

✔️AppConfig
package com.multi.spring3.config;
import org.apache.commons.dbcp2.BasicDataSource;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.SqlSessionTemplate;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;
import javax.sql.DataSource;
@Configuration
//@ComponentScan(basePackages = "com.multi")
public class AppConfig {
public AppConfig(){
System.out.println("AppConfig created");
}
@Bean
public DataSource dataSource() {
BasicDataSource dataSource = new BasicDataSource();
dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");
dataSource.setUrl("jdbc:mysql://localhost:3306/shop2?useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=UTC&characterEncoding=UTF-8&useUnicode=true");
dataSource.setUsername("root"); // mysql 아이디
dataSource.setPassword("0000"); // mysql 비밀번호
dataSource.setInitialSize(5); // 초기 커넥션 수
dataSource.setMaxTotal(10); // 최대 커넥션 수
return dataSource;
}
@Bean
public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception {
SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean();
sessionFactory.setDataSource(dataSource);
sessionFactory.setConfigLocation(new ClassPathResource("mybatis-config.xml"));
return sessionFactory.getObject();
}
@Bean
public SqlSessionTemplate sqlSessionTemplate(SqlSessionFactory sqlSessionFactory) {
return new SqlSessionTemplate(sqlSessionFactory);
}
}
✔️WebAppInitializer
package com.multi.spring3.config;
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;
public class WebAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
public WebAppInitializer(){
System.out.println("WebAppInitializer created");
}
@Override
protected Class<?>[] getRootConfigClasses() {
return new Class[] { AppConfig.class };
}
@Override
protected Class<?>[] getServletConfigClasses() {
return new Class[] { WebConfig.class };
}
@Override
protected String[] getServletMappings() {
return new String[] { "/" };
}
}
✔️WebConfig
package com.multi.spring3.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.filter.CharacterEncodingFilter;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.springframework.web.servlet.view.InternalResourceViewResolver;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import javax.servlet.Filter;
@Configuration
@EnableWebMvc
@ComponentScan(basePackages = "com.multi.spring3")
public class WebConfig implements WebMvcConfigurer {
public WebConfig(){
System.out.println("WebConfig created");
}
@Bean
public InternalResourceViewResolver viewResolver() {
InternalResourceViewResolver resolver = new InternalResourceViewResolver();
resolver.setPrefix("/WEB-INF/views/");
resolver.setSuffix(".jsp");
return resolver;
}
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/resources/**")
.addResourceLocations("/resources/");
}
}
💡Mapper

✔️mapper/MemberMapper
<?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.multi.spring3.member.mapper.MemberMapper">
<insert id="insert"
parameterType="com.multi.spring3.member.domain.MemberVO">
insert into member
values (#{id}, #{pw}, #{name}, #{tel});
</insert>
<update id="update"
parameterType="com.multi.spring3.member.domain.MemberVO">
update member set tel = #{tel}
where id = #{id}
</update>
<delete id="delete"
parameterType="String">
delete from member
where id = #{id}
</delete>
<select id="one"
parameterType="String"
resultType="com.multi.spring3.member.domain.MemberVO">
select * from member
where id = #{id}
</select>
<select id="all"
resultType="com.multi.spring3.member.domain.MemberVO">
select * from member
</select>
<select id="login"
parameterType="com.multi.spring3.member.domain.MemberVO"
resultType="int">
select count(id) from member
where id = #{id} and pw = #{pw}
</select>
<select id="find"
parameterType="String"
resultType="com.multi.spring3.member.domain.MemberVO">
select * from member
where id LIKE CONCAT('%', #{word}, '%')
</select>
</mapper>
| 태그 | 설명 | 예시 쿼리 |
| <insert> | 새로운 레코드 삽입 | insert into member (id, pw, name, tel) values (#{id}, #{pw}, #{name}, #{tel}); |
| <update> | 기존 레코드 업데이트 | update member set tel = #{tel} where id = #{id}; |
| <delete> | 레코드 삭제 | delete from member where id = #{id}; |
| <select> | 단일 또는 다중 레코드 조회 | select * from member where id = #{id}; <br> select * from member; |
| namespace | 고유 네임스페이스 정의 | com.multi.spring3.member.mapper.MemberMapper |
| id | 쿼리의 고유 ID | id="insert", id="update", id="delete", id="one", id="all" |
| parameterType | 파라미터 타입 지정 | parameterType="com.multi.spring3.member.domain.MemberVO" |
| resultType | 결과와 타입 지정 | resultType="com.multi.spring3.member.domain.MemberVO" |
| resultMap | 복잡한 매핑을 위한 결과와 매핑 정의 | <resultMap id="memberResultMap" type="com.multi.spring3.member.domain.MemberVO"> <id property="id" column="member_id"/> <result property="name" column="member_name"/> <result property="tel" column="member_tel"/> </resultMap> |
✔️mybatis-config.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<typeAliases>
<package name="com.multi.spring3.member.domain"/>
</typeAliases>
<mappers>
<mapper resource="mapper/memberMapper.xml"/>
</mappers>
</configuration>
💡DAO
package com.multi.spring3.member.dao
import com.multi.spring3.member.domain.MemberVO;
import com.multi.spring3.member.mapper.MemberMapper;
import org.mybatis.spring.SqlSessionTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import java.util.List;
@Repository
public class MemberDAO {
private final SqlSessionTemplate sqlSessionTemplate;
@Autowired
public MemberDAO(SqlSessionTemplate sqlSessionTemplate) {
this.sqlSessionTemplate = sqlSessionTemplate;
}
public int insert(MemberVO memberVO) {
return sqlSessionTemplate.getMapper(MemberMapper.class).insert(memberVO);
}
public MemberVO one(String id) {
return sqlSessionTemplate.getMapper(MemberMapper.class).one(id);
}
public int update(MemberVO memberVO) {
return sqlSessionTemplate.getMapper(MemberMapper.class).update(memberVO);
}
public int delete(String id) {
return sqlSessionTemplate.getMapper(MemberMapper.class).delete(id);
}
public List<MemberVO> all() {
return sqlSessionTemplate.getMapper(MemberMapper.class).all();
}
public int login(MemberVO memberVO) {
return sqlSessionTemplate.getMapper(MemberMapper.class).login(memberVO);
}
public List<MemberVO> find(String word) {
return sqlSessionTemplate.getMapper(MemberMapper.class).find(word);
}
💡Service
package com.multi.spring3.member.service;
import com.multi.spring3.member.dao.MemberDAO;
import com.multi.spring3.member.domain.MemberVO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class MemberService {
private final MemberDAO memberDAO;
@Autowired
public MemberService(MemberDAO memberDAO) {
this.memberDAO = memberDAO;
System.out.println("MemberService created");
}
public String insert(MemberVO memberVO){
String result = "회원가입 실패";
if(memberDAO.insert(memberVO) == 1){
result = "회원가입 성공";
};
return result;
}
public String update(MemberVO memberVO){
String result = "회원수정 실패";
if(memberDAO.update(memberVO) != 0){
result = "회원수정 성공";
};
return result;
}
public String delete(String id){
String result = "회원탈퇴 실패";
if(memberDAO.delete(id) != 0){
result = "회원탈퇴 성공";
};
return result;
}
public MemberVO one(String id){
return memberDAO.one(id);
}
public List<MemberVO> all(){
return memberDAO.all();
}
public int login(MemberVO memberVO) {
return memberDAO.login(memberVO);
}
public List<MemberVO> find(String word){
return memberDAO.find(word);
}
}
💡Controller
package com.multi.spring3.member.controller;
import com.multi.spring3.member.domain.MemberVO;
import com.multi.spring3.member.service.MemberService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpSession;
import java.util.List;
@Controller
@RequestMapping("/member")
public class MemberController {
private final MemberService memberService;
@Autowired
public MemberController(MemberService memberService) {
System.out.println("MemberController created");
this.memberService = memberService;
}
@GetMapping
public String index() {
return "member/member";
}
@PostMapping("/insert")
public ModelAndView insert(MemberVO memberVO) {
System.out.println(memberVO);
String result = memberService.insert(memberVO);
System.out.println("--------->> " + result);
ModelAndView modelAndView = new ModelAndView();
modelAndView.addObject("result", result);
modelAndView.setViewName("member/insert_result");
return modelAndView;
}
@PostMapping("/update")
public ModelAndView update(MemberVO memberVO) {
String result = memberService.update(memberVO);
System.out.println("--------->> " + result);
ModelAndView modelAndView = new ModelAndView();
modelAndView.addObject("result", result);
modelAndView.setViewName("member/update_result");
return modelAndView;
}
@GetMapping("/login")
public String login() {
return "member/login";
}
@GetMapping("/logout")
public String logout(HttpSession session) {
//세션끊기
session.invalidate();
return "redirect:/";
}
@PostMapping("/loginProcess")
public String loginProcess(MemberVO memberVO, HttpSession session) {
int result = memberService.login(memberVO);
System.out.println("--------->> " + result);
if (result == 1){
session.setAttribute("login_id", memberVO.getId());
return "member/login_ok";
}else{
return "member/login_no";
}
}
@PostMapping("/delete")
public ModelAndView delete(@RequestParam("id") String id) {
String result = memberService.delete(id);
System.out.println("--------->> " + result);
ModelAndView modelAndView = new ModelAndView();
modelAndView.addObject("result", result);
modelAndView.setViewName("member/delete_result");
return modelAndView;
}
@GetMapping("/one")
public ModelAndView one(String id) {
MemberVO memberVO = memberService.one(id);
System.out.println("--------->> " + memberVO);
ModelAndView modelAndView = new ModelAndView();
modelAndView.addObject("memberVO", memberVO);
modelAndView.setViewName("member/one_result");
return modelAndView;
}
@GetMapping("/all")
public ModelAndView all() {
List<MemberVO> all = memberService.all();
System.out.println("--------->> " + all);
ModelAndView modelAndView = new ModelAndView();
modelAndView.addObject("all", all);
modelAndView.setViewName("member/all_result");
return modelAndView;
}
@GetMapping("/find")
public ModelAndView find(@RequestParam("word") String word) {
List<MemberVO> all = memberService.find(word);
System.out.println("--------->> " + all);
ModelAndView modelAndView = new ModelAndView();
modelAndView.addObject("all", all);
modelAndView.setViewName("member/find_result");
return modelAndView;
}
}
💡View (member.jsp)

<%@ page contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Member CRUD Form</title>
<link rel="stylesheet" href="../resources/css/out.css">
</head>
<body>
<div class="container">
<h2>Member CRUD Form</h2>
<!-- Member Table -->
<table>
<thead>
<tr>
<th>항목명</th>
<th>입력폼</th>
</tr>
</thead>
<tbody>
<!-- Sample data row for demonstration -->
<tr>
<td class="center">회원가입</td>
<td>
<!-- Member Insert Form -->
<form action="member/insert" method="post">
<label for="id">ID</label>
<input type="text" id="id" name="id" value="apple" required>
<label for="pw">Password</label>
<input type="password" id="pw" name="pw" value="1234" required>
<label for="name">Name</label>
<input type="text" id="name" name="name" value="apple">
<label for="tel">Telephone</label>
<input type="text" id="tel" name="tel" value="011">
<button type="submit">Add Member</button>
</form>
</td>
</tr>
<tr>
<td class="center">회원탈퇴</td>
<td>
<!-- Member Delete Form -->
<form action="member/delete" method="post">
<input type="text" name="id" value="apple">
<button type="submit" class="btn-edit">Delete Member</button>
</form>
</td>
</tr>
<tr>
<td class="center">회원정보 수정</td>
<td>
<!-- Member Update Form -->
<form action="member/update" method="post">
<label for="id">Update Member by ID</label>
<input type="text" id="id" name="id" required>
<label for="tel">New Telephone</label>
<input type="text" id="tel" name="tel">
<button type="submit">Update Member</button>
</form>
</td>
</tr>
<tr>
<td class="center">회원정보 검색</td>
<td>
<!-- Member Search Form -->
<form action="member/one" method="get">
<label for="id">Search Member by ID</label>
<input type="text" name="id" value="apple" required>
<button type="submit">Search</button>
</form>
</td>
</tr>
<tr>
<td class="center">회원 전체 검색</td>
<td>
<!-- Member All -->
<a href="member/all">
<button>Search All</button>
</a>
</td>
</tr>
</tbody>
</table>
</div>
</body>
</html>
🎈ModelAndView 뜯어보기
✔️Controller 코드
ModelAndView modelAndView = new ModelAndView();
modelAndView.addObject("memberVO", memberVO); // --> 모델 속성으로 지정(이름, 값);
modelAndView.setViewName("member/one_result"); // --> 결과를 출력할 views/jsp파일 이름
✔️ View 코드 (views/jsp)
<%
MemberVO memberVO = (MemberVO)request.getAttribute("memberVO");
%>
// --> ${memberVO} -> 모델 속성으로 지정한 이름 출력
<table>
<thead>
<tr>
<th>항목명</th>
<th>항목값</th>
</tr>
</thead>
<tbody>
<tr>
<td>가입한 ID</td>
<td><%= memberVO.getId()%></td>
</tr>
<tr>
<td>가입한 PW</td>
<td><%= memberVO.getPw()%></td>
</tr>
<tr>
<td>가입한 NAME</td>
<td><%= memberVO.getName()%></td>
</tr>
<tr>
<td>가입한 TEL</td>
<td><%= memberVO.getTel()%></td>
</tr>
</tbody>
</table>
전체 코드 보러가기
https://github.com/mimmmji/myBatis
GitHub - mimmmji/myBatis: Spring & MyBatis & JSP: 간단한 회원 관리 및 게시판(CRUD) 구현 코드
Spring & MyBatis & JSP: 간단한 회원 관리 및 게시판(CRUD) 구현 코드 - mimmmji/myBatis
github.com
구현 영상
💡느낀점
오늘은 MyBatis와 JSP, Spirng을 사용하여 간단한 회원관리를 하는 실습을 하는 과정에 대하여 정리해보았다 !
코드가 많아 주요 코드에 대해서만 적어보았는데, 처음으로 제대로 데이터베이스를 연동하여 실제 프로젝트에 사용해볼 수 있는 코드가 완성된 것 같아 매우 뿌듯하였다 😊
지금은 JSP를 사용하여 View를 구현중이지만, 다음에는 Vue와 연동하여 View를 구현할 예정이다 !
이해가 안되는 부분이 있으시다면 댓글로 남겨주시면 최대한 빠른 답글 남기도록 하겠습니다
조금 더 달려보자 홧팅 🚗🚗🚗

'[KB IT's Your Life] Today I Learnd' 카테고리의 다른 글
| [KB IT's Your Life] 6주차 컴포넌트 백엔드: 게시판 만들기💡 (3) | 2024.09.02 |
|---|---|
| [KB IT's Your Life] 5주차 컴포넌트 백엔드: Rest 실습 프로젝트💡 (0) | 2024.08.26 |
| [KB IT's Your Life] 3주차 컴포넌트 백엔드2 💡 (6) | 2024.08.12 |
| [KB IT's Your Life] 2주차 컴포넌트 백엔드 💡 (2) | 2024.08.03 |
| [KB IT's Your Life] 1주차 데이터베이스 활용 & 모델링 💡 (1) | 2024.07.27 |