myBatis는 SQL 매퍼 프레임워크입니다. '매퍼 프레임워크'.. 단어가 어렵지요?
단어는 차치하고 myBatis는 왜 개발됐을까요? myBatis는 JDBC 단점 때문에 등장했습니다. JDBC의 단점은 뭘까요?
① 중복 코드 작성(getConnection, close)
② SQL 구문이 DAO에 포함
JDBC 장·단점이 궁금하시다면..🧷
myBatis는 이 두가지 문제를 해결했습니다.
① 더이상 중복 코드를 작성하지 않아도 되죠. Connection, close를 myBatis가 대신 처리합니다.
② SQL이 변경되더라도 자바 소스를 변경하지 않아도 됩니다. SQL 구문은 xml 파일을 만들어서 관리합니다.
DB연동이 얼마나 편해졌는지 한번 살펴볼까요?
실습 순서는 다음과 같습니다.
① VO(Value Object) 작성
② SQL Mapper 작성
③ myBatis 메인 설정 파일 작성
④ DAO(Data Access Object) 작성
⑤ Client 작성
VO는 JDBC 실습에서 사용한 것과 동일합니다.
package com.rubypaper.persistence.mybatis;
import lombok.Data;
import java.sql.Timestamp;
@Data
public class EmployeeVO {
private Long id;
private String name;
private Timestamp startDate;
private String title;
private String deptName;
private Double salary;
}
SQL Mapper XML 등록된 SQL은 중복되지 않는 id를 가져야 합니다. (아래에서는 insertEmployee, getEmployeeList라고 작성했습니다.
insertEmployee는 parameterType으로 employeeVO 객체를 받아서 바인딩하고 있습니다. (코드에서 employee는 EmployeeVO의 별칭(Alias)입니다. myBatis 메인 설정파일에서 별칭을 선언할 수 있습니다.)
getEmployeeList는 파라미터가 없어서 parameterType 속성을 사용하지 않았습니다. 검색 결과가 EmployeeVO 객체에 매핑되도록 resultMap 속성을 사용했습니다.
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//matabis.org//DTD Mapper 3.0//EN" "http://mabatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="EmployeeDAO">
<!--ResultMap 선언-->
<resultMap type="" id="employeeResult">
<result property="id" column="ID"/>
<result property="name" column="NAME"/>
<result property="startDate" column="START_DATE"/>
<result property="title" column="TITLE"/>
<result property="deptName" column="DEPT_NAME"/>
<result property="salary" column="SALARY"/>
</resultMap>
<!--직원 등록 SQL-->
<insert id="insertEmployee" parameterType="employee">
INSERT INTO s_emp(id, name, start_date, title, dept_name, salary)
VALUES((SELECT nvl(max(id), 0) + 1 FROM s_emp),
#{name},
#{startDate},
#{title},
#{deptName},
#{salary},
</insert>
<!--직원 목록 검색 SQL-->
<select id="getEmployeeList" resultMap="employeeResult">
SELECT id, name, start_date, title, dept_name, salary
FROM s_emp
ORDER BY name
</select>
</mapper>
① 별칭(Alias)를 설정합니다. 별칭은 SQL Mapper XML(s_emp_mapping.xml)에서 사용합니다.
② 데이터 소스를 설정합니다. 여기서는 H2 DB를 설정했습니다.
③ SQL Mapper XML(s_emp-mapping.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>
<!--매퍼 XML(s_emp_mapping.xml)에서 사용할 Alias 선언-->
<typeAliases>
<typeAlias alias="employee" type="com.rubypaper.persistence.mybatis.EmployeeVO"/>
</typeAliases>
<!--데이터소스 설정-->
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"></transactionManager>
<dataSource type="POOLED">
<property name="driver" value="org.h2.Driver"/>
<property name="url" value="jdbc:h2:tcp://localhost/~/test"/>
<property name="username" value="sa"/>
<property name="password" value=""/>
</dataSource>
</environment>
</environments>
<!--매퍼 XML(s_emp_mapping.xml) 등록-->
<mappers>
<mapper resource="com/rubypaper/persistence/mybatis/s_emp_mapping"/>
</mappers>
</configuration>
myBatis를 사용하려면 SqlSession 객체가 필요합니다. SqlSession 객체는 아래 방법으로 얻을 수 있습니다. (SqlSession에는 데이터 소스와 sql-map-config.xml에 설정한 정보가 들어 있습니다.)
① sql-map-config.xml을 로딩해서 SqlSessionFactory를 생성합니다.
② SqlSessionFactory의 openSession()을 통해 SqlSession을 생성합니다.
package com.rubypaper.persistence.mybatis;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import java.io.IOException;
import java.io.Reader;
import java.util.List;
public class EmployeeDAO {
private SqlSession mybatis;
public EmployeeDAO() {
try {
Reader reader = Resources.getResourceAsReader("com/rubypaper/persistence/mybatis/sql-map-config.xml");
SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(reader);
mybatis = sessionFactory.openSession();
} catch (IOException e) {
e.printStackTrace();
}
}
public void insertEmployee(EmployeeVO vo) {
System.out.println("===> MyBatis 기반으로 회원 등록");
mybatis.insert("EmployeeDAO.insertEmployee", vo);
mybatis.commit();
}
public List<EmployeeVO> getEmployeeList() {
System.out.println("===> MyBatis 기반으로 회원 목록 조회");
return mybatis.selectList("EmployeeDAO.getEmployeeList");
}
}
Client는 DAO에 구현된 메서드의 기능을 확인합니다.
package com.rubypaper.persistence.mybatis;
import java.sql.Timestamp;
import java.util.List;
public class EmployeeServiceClient {
public static void main(String[] args) {
EmployeeVO vo = new EmployeeVO();
vo.setName("둘리");
vo.setStartDate(new Timestamp(System.currentTimeMillis()));
vo.setTitle("사원");
vo.setDeptName("영업부");
vo.setSalary(1700.00);
EmployeeDAO employeeDAO = new EmployeeDAO();
employeeDAO.insertEmployee(vo);
List<EmployeeVO> employeeList = employeeDAO.getEmployeeList();
for (EmployeeVO employee : employeeList) {
System.out.println("---> " + employee.toString());
}
}
}
JDBC에 비해 코드가 한결 간결해졌습니다. 그러나 여전히 SQL을 직접 관리해야 하는 번거로움이 있습니다.
myBatis의 단점을 보완하기 위해 ORM(Object-Relational Mapping) Framework가 등장했습니다. 다음 글에서는 ORM Framework 중 Hibernate로 DB 연동을 해보겠습니다.
JPA 퀵스타트
채규태 지음ㅣ루비페이퍼ㅣ2020ㅣ도서 정보