웹 개발

[Web] Mybatis에 관해

빡수수 2022. 6. 9. 21:56

MyBatis

1) MyBatis란?

마이 바티스(MyBatis)란 자바의 프레임워크 중 하나로 XML이나 애너테이션(annotation)을 사용하여 저장 프로시저나 SQL문으로 객체들을 연결시킬 수 있는 소프트웨어이다. 마이 바티스에서는 프로그램에 있는 SQL 쿼리들을 한 구성 파일에 구성하여 프로그램 코드와 SQL을 분리할 수 있는 장점을 지닌다. 마이 바티스를 활용하면 복잡한 JDBC 코드를 깔끔하게 정리할 수 있다는 장점이 있다. XML 형태로 작성된 JDBC 코드라고 말할 정도로 JDBC의 모든 기능을 제공한다.

 

2) MyBatis 활용

부서목록 테이블 출력

간단하게 위의 이미지처럼 오라클에 저장된 부서테이블의 부서 번호, 부서 이름, 부서위치를 출력해보려 한다.

--부서테이블
CREATE TABLE DEPT(
	DEPTNO NUMBER(3) PRIMARY KEY, --부서번호
	DNAME VARCHAR2(10), --부서명
	LOCATION VARCHAR2(5) --부서위치
);

INSERT INTO DEPT VALUES(10, '총무부', '101');
INSERT INTO DEPT VALUES(20, '영업부', '202');
INSERT INTO DEPT VALUES(30, '전산실', '303');
INSERT INTO DEPT VALUES(40, '관리부', '404');
INSERT INTO DEPT VALUES(50, '경리부', '505');

테이블 구조와 필요한 데이터들을 기존에 오라클에 넣어주었다. 위의 코드에는 나와있지 않지만, 데이터를 입력하는 Insert 구문을 작성한 뒤에는 반드시 Commit을 해주자.

package vo;

public class DeptVO {
	private int deptno;
	private String dname, location;
	
	public int getDeptno() {
		return deptno;
	}
	public void setDeptno(int deptno) {
		this.deptno = deptno;
	}
	public String getDname() {
		return dname;
	}
	public void setDname(String dname) {
		this.dname = dname;
	}
	public String getLocation() {
		return location;
	}
	public void setLocation(String location) {
		this.location = location;
	}
	
	
}

위의 코드는 오라클에 입력한 부서 번호, 부서 이름, 부서위치를 활용하기 위한 클래스이다.

package dao;

import java.util.List;

import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;

import service.MyBatisConnector;
import vo.DeptVO;

public class DeptDAO {

	SqlSessionFactory factory;
	
	// single-ton pattern: 
	// 객체1개만생성해서 지속적으로 서비스하자
	static DeptDAO single = null;

	public static DeptDAO getInstance() {
		//생성되지 않았으면 생성
		if (single == null)
			single = new DeptDAO();
		//생성된 객체정보를 반환
		return single;
	}
	
	public DeptDAO() {
		//커넥터에서 디비의 접근할 수 있는 내용을 알고 있는 팩토리를 받아옴
		factory = MyBatisConnector.getInstance().getFactory();
	}
	
	//부서테이블 조회
	public List<DeptVO> select() {
		
		//SqlSession : DB에 쿼리문을 실제로 요청하는 객체
		SqlSession sqlSession = factory.openSession();

		//DB접근을 통해 얻어온 결과를 list에 저장
		List<DeptVO> list =sqlSession.selectList("dept.dept_list");
	
		//DB접근을 위해 사용한 sqlSession은 마지막에 꼭 닫아줘야함
		sqlSession.close();
		return list;
	}
	
}

다음은 데이터베이스에 실질적으로 연동하는 코드를 작성한 DeptDAO.java 파일이다. 싱글톤 형태로 작성하여 객체를 하나만 사용하여 다른 코드에서도 자유롭게 사용할 수 있도록 작성하였다. 이후 생성자를 통해 커넥터에서 디비에 접근할 수 있는 내용을 알고 있는 팩토리를 받아온 뒤 아래에 select()라는 조회 메서드를 만들어주었다. 메서드 안에는 SqlSession을 사용하여 디비에 쿼리문을 요청하고, 전에 만들어둔 vo클래스를 통해 결과들을 리스트 형식으로 저장한다. 

만약, 조회가 아니라 INSERT, UPDATE, DELETE 등 다양한 디비 작업들을 하려면 아래에 메서드 형식으로 추가해주면 된다.

<?xml version="1.0" encoding="UTF-8"?>
<Context>
	<Resource 
	        auth="Container" 
      		name="jdbc/oracle_test"
      		type="javax.sql.DataSource"
      		driverClassName="oracle.jdbc.driver.OracleDriver"
      		factory="org.apache.commons.dbcp.BasicDataSourceFactory"
      		url="jdbc:oracle:thin:@localhost:1521:xe"
      		username="유저명입력" password="비밀번호입력" 
      		maxActive="20" maxIdle="10" maxWait="1"/>
</Context>

자바와 데이터베이스를 연결하는 방식은 여러 가지겠지만, 이번엔 context.xml을 만들어주어, 미리 세팅을 해주었다.

username과 password 부분에 본인의 오라클 유저명과 비밀번호를 입력해주면 된다.

<?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>
	<environments default="">
		<environment id="">
			<transactionManager type="JDBC" />
			
			<!-- mybatis 사용을 위해서 JNDI를 찾아주는 코드 -->
			<!-- context.xml으로 접근하고 context.xml에 작성된 계정으로 로그인해주는 방식 -->
			<dataSource type="JNDI">
				<!-- jdbc~~부분은 context.xml의 이름을 작성해주면 됨. -->
				<property name="data_source" 
				value="java:comp/env/jdbc/oracle_test" />
			</dataSource>
		</environment>
	</environments>
	<mappers>
		<mapper resource="config/mybatis/mapper/dept.xml" /> 
	</mappers>
</configuration>

다음으로 위의 코드는 마이 바티스를 사용하기 위한 기본 셋팅이라고 보면 될 것같다. 마이바티스를 사용하기 위해서 JNDI를 찾아주는 코드로, context.xml에 작성된 계정으로 로그인해주는 방식이다. 이후 mapper부분에 sql문을 작성해둔 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="dept">
<!-- mapper : DB에 쿼리문을 요청하고 결과를 돌려받는 속성파일 -->
<select id="dept_list" resultType="vo.DeptVO">
	select * from dept
</select>
 
</mapper>

위에서 언급했던 sql문을 작성해둔 xml파일이다. mapper의 namespace를 dept로 해주었고, 우린 부서 목록을 조회를 할 것이기 때문에 select를 사용하고, id는 dept_list로 지정했다. 또한 resultType을 vo클래스로 하였다.

아까 위의 DeptDAO.java 파일에서 sqlSession.select() 코드를 작성할 때 위 코드의 mapper의 namespace와 select의 id를.으로 연결하여 작성한 것이다.

여기서 가장 주의해야 할 점은 오라클에서처럼 ;(세미콜론)을 작성하면 안 된다는 것이다. 이 점만 명심하자.

<%@ 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>Insert title here</title>
</head>
<body>
	<table border="1">
		<caption>:::부서목록:::</caption>
		<tr>
			<th>부서번호</th>
			<th>부서이름</th>
			<th>부서위치</th>
		</tr>
		<c:forEach var="vo" items="${list }">
			<tr>
				<td>${vo.deptno }</td>
				<td>${vo.dname }</td>
				<td>${vo.location }</td>
			</tr>
		</c:forEach>
		
	</table>
</body>
</html>

위 코드는 우리가 최종적으로 보여주고 싶은 화면의 틀을 작성한 코드이다. table을 활용하여 캡션과 head부분을 작성해주었고, 안에 들어갈 데이터는 forEach를 활용하여 list의 길이만큼 반복하여 출력하도록 하였다.

package action;

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;

import dao.DeptDAO;
import vo.DeptVO;

/**
 * Servlet implementation class DeptListAction
 */
@WebServlet("/dept_list.do")
public class DeptListAction extends HttpServlet {
	private static final long serialVersionUID = 1L;

	/**
	 * @see HttpServlet#service(HttpServletRequest request, HttpServletResponse response)
	 */
	protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		// 부서목록 가져오기
		List<DeptVO> list = DeptDAO.getInstance().select();
		
		//list 바인딩
		request.setAttribute("list", list);
		
		//포워딩
		RequestDispatcher disp = request.getRequestDispatcher("dept_list.jsp");
		disp.forward(request, response);
		
		
	}

}

마지막으로 서블릿 파일이다. 매핑명은 dept_list.do로 설정해주었고, 위에 작성한 DAO를 활용하여 부서 목록 리스트를 가져온다. 이후 이 리스트를 바인딩하여 jsp파일로 포워딩해주는 코드이다. 데이터베이스에서 올바르게 데이터를 받아와 화면에 출력하기 위해서는 dept_list.jsp를 실행시키는 것이 아니라, 서블릿 파일을 실행시켜야 데이터들이 함께 출력되니 이 점도 주의하자!

마치며

오늘은 마이 바티스를 활용하여 간단한 부서 목록을 출력하는 예제를 해보았다. 출력은 간단하지만, 필요한 코드가 한 두 개가 아니고, 여러 파일에서 데이터들이 이동하는 것이 가장 이해하기 어려웠다. 

나머지 전반적인 흐름은 어느 정도 이해가 되지만, 사실 가장 이해가 안 되는 부분은 xml코드이다. xml코드를 좀 더 분석하며 다른 예제들을 추가적으로 해볼 계획이다.