- 9일 월요일에 MyBatis를 배웠다. 화요일과 수요일에는 지난 주에 진행했던 프로젝트에 MyBatis를 적용하는 작업을 했다.
- 일반적으로 MyBatis는 자바에서 자주 사용되는 ORM(Object relational Mapping) 프레임워크라고 소개된다. ORM이란 관계형 DB의 테이블 속 각 행을 데이터를 표현하는 객체에 자동으로 맵핑해주는 것을 의미한다.
- 예컨대, JDBC와 커넥션 풀을 직접 사용했던 기존 프로젝트에서 SELECT 문을 실행한 뒤 이를 VO에 담기 위해서는 아래와 같이 했어야 했다.
기존 DAO 소스코드 일부
public AccountVO selectByUsername(String username) {
String sql = "SELECT * FROM accountsTBL WHERE ausername = ? AND adisabled = FALSE";
AccountVO account = null;
PreparedStatement pstmt = null;
try {
pstmt = con.prepareStatement(sql);
pstmt.setString(1, username);
ResultSet rs = pstmt.executeQuery();
if (!rs.isBeforeFirst() ) {
return null;
} else {
rs.next();
account = new AccountVO(rs.getInt("ano"), rs.getString("aname"), rs.getString("adepartment"), rs.getString("abirth"), rs.getString("acreatedAt"), rs.getString("aphone"),
rs.getString("aemail"), rs.getString("aaddr"), rs.getInt("apoint"), rs.getInt("alevel"), rs.getString("ausername"), rs.getString("apassword"));
}
} catch (SQLException e) {
e.printStackTrace();
}
return account;
}
- ResultSet으로부터 각 컬럼명을 통해 일일이 해당 컬럼에 대한 값을 얻어 생성자에 넣어주고 있다. 여간 번거로운 것이 아니다. 이를 MyBatis를 이용하여 아래와 같이 고칠 수 있다.
수정 DAO 소스코드 일부
public AccountVO selectOne(AccountVO targetAccount) {
AccountVO foundAccount = null;
try {
foundAccount = session.selectOne("liverary.account.select", targetAccount);
} catch (Exception e) {
throw e;
}
return foundAccount;
}
Mapper 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="liverary.account">
<select id="select"
parameterType="Account" resultType="Account">
SELECT * FROM accountsTBL
<if test='ano != 0' >
WHERE ano = #{ano}
</if>
<if test='ausername != null' >
WHERE ausername = #{ausername}
</if>
<if test='aname != null' >
WHERE aname = #{aname}
</if>
<if test='alevel >= 1' >
<![CDATA[
AND alevel >= 1
]]>
</if>
AND adisabled = FALSE
</select>
<!-- 후략 -->
- 조회한 값을 바로 VO에 할당해줄 뿐 아니라, SQL 문을 Java 소스 코드 외부의 XML에서 별도로 관리할 수 있게 되었으며,
-
태그를 통해 파라미터를 조건부로 취급하여 DAO 클래스 내의 메서드 수를 대폭 줄일 수 있게 되었다. - 예컨대 똑같이 DAO의 selectOne()이 호출되었다고 해도, VO에 ano가 set 된 경우 WHERE 절에 ano를 걸어 조회하고, ausername이 set 된 경우 WHERE 절에 ausername을 걸어 조회하게 된다.
- 최대한 오류 없이 기존 프로젝트를 리팩토링 하기 위해, 아래와 같이 작업하였다.
- 우선 기존 DAO 파일을 접미사 _OLD를 붙여 복사한다. 그럼 다른 클래스에서 해당 DAO를 참조한 경우 이클립스가 알아서 새로운 파일의 이름으로 변경해준다.
- 원래 DAO 이름으로 생성자와 필드(SqlSession)만을 가진 새로운 DAO 파일을 만든다.
- AccountService, LoanService, BookService 각각을 순서를 지켜 하나씩 수정해나가기 시작한다. 도메인별로 수정하여 에러의 범위를 해당 도메인으로 국한시키기 위해서이다.
- 서비스의 메서드 각각을 다시 분석하며
등 동적 쿼리로 묶을 수 있는 메서드가 있는지 확인한다. - 서비스의 각 메서드를 수정하면서 분석 내용을 바탕으로 필요한 DAO 메서드를 작성하며, 함께 Mapper XML을 작성한다.