10. 스프링 프레임워크 - MyBatis[자바웹을 다루는 기술]
MyBatis란?
마이바티스는 자바 퍼시스턴스 프레임워크의 하나로 XML 서술자나 에너테이션을 사용하여 저장 프로시저나
SQL 문으로 객체를을 연결 시킨다 - 위키백과-
사전적 정의는 뭐 이렇다고 합니다. 결론 부터 얘기 하자면 기존의 JDBC 방식으로 이용하면 프로젝트가 커질 수 록
코드자체가 너무 복잡해져서 가독성이 떨어지고 유지보수에 어려움이 있기 때문입니다. 왜냐면 SQL문과 프로그래밍 코드가 섞여 있기 때문 입니다.
이런 문제점을 개선해 나온게 MyBatis 입니다.
public void addGoods(GoodsVO goodsVO) throws SQLException {
Connection con = dataFactory.getConnection();
Statement stmt = con.createStatementO;
String query = "insert into t_goods_info (goods_id,"+
"goods_sortj"+
"goods_title/'+
"goods_writer,"+
"goods_publisher,"+
"goods_price,"+
"goods_sales_price,"+
"goods_point,"+
"goods_published_date,"+
"goods_total_page,"+
"goods_isbn,"+
"goods_deUvery_price, "+
"goods_delivery_date,"+
"goods_type,"+
"goods_writer_intro,"+
"goods_intro,"+
"goods_publisher_commentj"+
"goods_recommendation,"+
"goods_contents_order)";
query+=" values("'+
goodsV0.get6oods_id()+"',
goodsVO.getGoods_sort()+"',
goodsVO.getGoods_title()+"',
goodsVO.getGoods_writer()+"'/ "+
goodsVO. getGoods_pubUsher()+"',"+
goodsVO.getGoods_price()+","+
goodsVO.getGoods_sales_price()+","+
goodsVO.getGoods_point()+"j'"+
goodsVO.getGoods_published_date()+"',"+
goodsVO.getGoods_page_total()+",'"+
goodsVO.getGoods_isbn()+'","+
goodsVO.getGoods_delivery_price()+",'"+
goodsVO.getGoods_delivery_date()+"','
goodsVO.getGoods_type()+"',
goodsVO.getGoods_writer_intro()+"',
goodsVO.getGoods_intro()+"',
goodsVO.getGoods_publisher_coinment()+"','
goodsVO.getGoods_recommendation()+"',
goodsVO.getGoods_contents_order()+"'
System.out.println(query);
stmt.executeUpdate(query);
String goods_id=goodsVO.getGoods_id();
}
너무 복잡합니다.. 이렇게 긴 SQL문을 String 문자열로 하나씩 연결해서 사용한다면 불편할 뿐 만아니라, 유지보수 시에도 엄청난 시간을 소비해야합니다.

하지만 myBatis를 사용한다면 SQL Developer 같은 도구에서 사용하는 표준환된 방법으로 SQL문을 사용 할 수 있습니다.
MyBatis 특징
1. SQL 실행 결과를 자바 빈즈 또는 Map 객체에 매핑해 주는 Persistence 솔루션으로 관합니다.
즉, SQL문과 프로그래밍 코드를 분리해서 구현 합니다.
2. SQL문과 프로그래밍 코드를 분리 -> 분리를 통해서 가독성이 높아지고 유지보수가 쉬워짐
3. 데이터소스 기능과 트랜잭션 처리 기능을 제공 합니다.
*Persistece Framwork
- JDBC 프로그래밍의 복잡한 작업없이 간단한 작업만으로 데이터베이스와 연동되는 시스템을 빠르게 개발 및
안정적인 구동을 보장
Ex) MyBatis, JPA, Hibernate
MyBtis 구조
1. MyBatis 설치 및 lib 등록
lib에 마이바티스 jar 파일 등록 합니다.
아래 JSTL 파일은 실습에 필요한 파일 입니다.(영향 X)
MyBatis 관련 설정 파일
설정파일 | 기능 |
SqlMapConfig.xml | 데이터베이스 연동 시 반환되는 값을 저장할 빈이나 트랜잭션, 데이터소스 등 마이바티스 관련 정보를 설정 합니다. |
member.xml | 회원 정보 관련 SQL문을 설정 합니다.(mapper) |
3. member.xml 및 SqlMapConfig.xml 파일 생성
SqlMapConfig.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>
<!--DAO에서 SQL문으로 값을 전달할 때 또는 SQL문을 실한후 가져온 값을 DAO로 전달 할때 상용할 빈을 생성 -->
<typeAliases>
<typeAlias type="com.spring.ex01.MemberVO" alias="memberVO"/>
</typeAliases>
<!--데이터베이스 연결 설정 -->
<environments default="development">
<environment id="development">
<transactionManager type="JDBC" />
<dataSource type="POOLED">
<property name="driver" value="oracle.jdbc.driver.OracleDriver"/>
<property name="url" value="JDBC:oracle:thin:@localhost:1521:xe"/>
<property name="username" value="scott"/>
<property name="password" value="1234"/>
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="mybatis/mappers/member.xml"/>
</mappers>
</configuration>
1. <typeAlias> 태그는 어플케이션에서 SQL문으로 값을 전달하거나, 마이바티스에서 DBMS로 SQL문 실행시 반환되는 값을 저장하는 Bean을 생성 합니다.
2. 데이터베이스를 연결 하기위한 데이터소스를 설정합니다.
3. <mapper> SQL문을 실행 시키는 xml 파일 위치를 지정 합니다.
member.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="mapper.member">
<resultMap type="memberVO" id="memResult">
<result property="id" column="id"/>
<result property="pwd" column="pwd"/>
<result property="name" column="name"/>
<result property="email" column="email"/>
<result property="joinDate" column="joinDate"/>
</resultMap>
<!-- SQL 문의 >,<,<=,>= 같은 연산자들 XML파일에서 작성하면 연산자가 아닌 특수 문자로 인식, 오류 발생 <!CDATA[[]]> -->
<!-- DAO에서 id를 이용해서 해당 SQL문을 호출, 반환되는 레코드를 memResult에 저장 -->
<select id="selectAllMemberList" resultMap="memResult">
<![CDATA[
SELECT * FROM t_member order by joinDate desc
]]>
</select>
<mapper>
1. 다른 xml 파일의 SQL문과 구별하기 위해 네임스페이스를 지정합니다.
2. 회원정보를 지정할 resultMap을 지정 합니다.
3. select의 id 속성을 통해 DAO에서 SQL문을 구분해서 호출하는 용도로 사용합니다.
resultMap은 select하여 조회한 정보 값을 저장합니다.
마이바티스를 통해 회원 정보 조회
마이바티스와 연동할 파일들을 준비 합니다.
1. MemberDAO.java
2. MemberServlet.java
3. MemberVO.java
4. listMembers.jsp
1. MemberServlet.java
package com.spring.ex01;
import java.io.IOException;
import java.util.List;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* Servlet implementation class MemberServlet
*/
// mem.do로 요청
@WebServlet("/mem.do")
public class MemberServlet extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doHandle(request, response);
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doHandle(request, response);
}
protected void doHandle(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
request.setCharacterEncoding("utf-8");
response.setContentType("text/html;charset=utf-8");
MemberDAO dao = new MemberDAO();
List membersList = dao.selectAllMemberList();
request.setAttribute("membersList", membersList);
RequestDispatcher dispatch = request.getRequestDispatcher("test01/listMembers.jsp");
dispatch.forward(request, response);
}
}
1. get방식과 post방식에 따라 doHandle() 메서드 호출하도록 지정합니다.
2. MemberDAO의 selectAllMemberList() 메서드를 호출 합니다.
3. 호출한 메서드를 membersList라는 이름으로 request에 바인딩 합니다.
4. 바인딩된 정보를 RequestDispatcher클래스를 이용하여 forward 시킵니다(정보를 넘겨줌, 지정한 jsp로)
2. MemberDAO.java
package com.spring.ex01;
import java.io.IOException;
import java.io.Reader;
import java.util.List;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
public class MemberDAO {
//여러 차례 다시 빌드하지 않는것이 가장 좋은 형태 (싱글톤 패턴이나, static 싱긅턴 패턴 사용)
private static SqlSessionFactory sqlMapper = null;
public static SqlSessionFactory getInstance() {
if(sqlMapper==null) {
//MemberDAO의 각 메서드 호출 시 src/mybatis/SqlMapConfig.xml에서 설정 정보를 읽은 후 데이터베이스의 연동 준비를 함
String resource = "mybatis/SqlMapConfig.xml";
try {
Reader reader = Resources.getResourceAsReader(resource);
// 마이바티스를 이용하는 sqlMapper 객체를 가져옴
sqlMapper = new SqlSessionFactoryBuilder().build(reader);
} catch (Exception e) {
e.printStackTrace();
}
}
return sqlMapper;
}
public List<MemberVO> selectAllMemberList(){
sqlMapper = getInstance();
//실제 member.xml의 SQL 문을 호출하는 데 사용되는 SqlSession 객체를 가져옴
SqlSession session = sqlMapper.openSession();
List<MemberVO> memlist=null;
//여러 개의 레코드를 조회하므로 selectList() 메서드에 실행하고자 하는 sql문의 id를 인자로 전달
memlist = session.selectList("mapper.member.selectAllMemberList");
return memlist;
}
}
1. getInstance() 메서드는 SqlMapConfig.xml에서 설정 정보를 읽어 데이터베이스와 연동할 준비를 하는 메서드 입니다.
2. selectAllMmeberList() 메서드를 호출 하면 member.xml에서 설정한 네임스페이스와 id를 통해 해당 SQL문을 실행 합니다.
3. MemberVO
package com.spring.ex01;
import java.util.Date;
public class MemberVO {
private String id;
private String pwd;
private String name;
private String email;
private Date joinDate;
public MemberVO() {
}
public MemberVO(String id, String pwd, String name, String email) {
this.id = id;
this.pwd = pwd;
this.name = name;
this.email = email;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getPwd() {
return pwd;
}
public void setPwd(String pwd) {
this.pwd = pwd;
}
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;
}
public Date getJoinDate() {
return joinDate;
}
public void setJoinDate(Date joinDate) {
this.joinDate = joinDate;
}
}
SQL문에서 반환되는 값들이 저장되는 VO 클래스를 생성 합니다.
4. listMembers.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>회원 정보 창</title>
</head>
<body>
<table border="2">
<tr align="center">
<td>아이디</td>
<td>비밀번호</td>
<td>이름</td>
<td>이메일</td>
<td>가입일</td>
</tr>
<c:forEach var="member" items="${membersList }">
<tr align="center">
<td>${member.id }</td>
<td>${member.pwd }</td>
<td>${member.name }</td>
<td>${member.email }</td>
<td>${member.joinDate }</td>
</tr>
</c:forEach>
</table>
</body>
</html>
Controller에서 request에 바인딩한 memsList값을 이용해 속성 값들을 화면에 출력합니다.
결과를 실제로 확인해 보시길 바랍니다.
#마무리
큰 흐름을 정확하게 이해하고 가는 것이 중요하다. 현재 스프링MVC관련 구조는 실습한것과 크게 다르지는 않다.
다만 connection을 어떻게 했는가, JPA를 사용하는가, JSP말고 다른 것을 사용했을수도 있다.
매번 언급하지만, 암기식 방법은 좋지 않은 습관이다, 논리적으로 최대한 이해하도록 노력해야 합니다.
그리고 필자는 VO, DTO의 구분을 매우 헷갈려 합니다. 이 부분을 따로 공부해보시길 추천 드립니다.