MyBatis 프레임워크 개요
MyBatis란?
MyBatis는 SQL 매핑 프레임워크로, Java 객체와 SQL 문 사이의 자동 매핑을 지원한다. 기존 JDBC의 복잡한 코드를 간소화하고, SQL과 Java 코드의 분리를 통해 유지보수성을 향상시킨다.
핵심 구성 요소
- SqlSession: MyBatis의 핵심 인터페이스
- Mapper XML: SQL 문을 정의하는 파일
- Configuration: MyBatis 설정 파일
DAO 패턴 비교 분석
JDBC 방식의 DAO (기존 방식)
package com.kh.jsp.model.dao;
import static com.kh.jsp.common.JDBCTemplate.close;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Properties;
import com.kh.jsp.model.vo.Member;
public class MemberDao {
private Properties prop = new Properties();
public MemberDao() {
super();
String path = JDBCTemplate.class.getResource("/db/sql/member-mapper.xml").getPath();
try {
prop.loadFromXML(new FileInputStream(path));
} catch (IOException e) {
e.printStackTrace();
}
}
public Member loginMember(String userId, String userPwd, Connection conn) {
Member m = null;
PreparedStatement pstmt = null;
ResultSet rset = null;
String sql = prop.getProperty("loginMember");
try {
pstmt = conn.prepareStatement(sql);
pstmt.setString(1, userId);
pstmt.setString(2, userPwd);
rset = pstmt.executeQuery();
if(rset.next()) {
m = new Member(
rset.getInt("MEMBER_NO"),
rset.getString("MEMBER_ID"),
rset.getString("MEMBER_PWD"),
rset.getString("MEMBER_NAME"),
rset.getString("PHONE"),
rset.getString("EMAIL"),
rset.getString("ADDRESS"),
rset.getString("INTEREST"),
rset.getDate("ENROLL_DATE"),
rset.getDate("MODIFY_DATE"),
rset.getString("STATUS")
);
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
close(rset);
close(pstmt);
}
return m;
}
}
JDBC 방식의 특징
- Connection 객체를 직접 관리
- PreparedStatement, ResultSet 수동 처리
- 예외 처리 코드가 복잡
- SQL과 Java 코드가 분리되지 않음
MyBatis 방식의 DAO (현재 프로젝트)
package com.kh.mybatis.model.dao;
import org.apache.ibatis.session.SqlSession;
import com.kh.mybatis.model.vo.Member;
import java.util.HashMap;
public class MemberDao {
public Member loginMember(SqlSession sqlSession, String userId, String userPwd) {
HashMap<String, String> map = new HashMap<>();
map.put("memberId", userId);
map.put("memberPwd", userPwd);
Member loginMember = sqlSession.selectOne("MemberMapper.loginMember", map);
return loginMember;
}
public int updateMemberPwd(SqlSession sqlSession, String memberId, String updatePwd) {
HashMap<String, String> map = new HashMap<>();
map.put("memberId", memberId);
map.put("updatePwd", updatePwd);
return sqlSession.update("MemberMapper.updateMemberPwd", map);
}
}
MyBatis 방식의 특징
- SqlSession을 통한 간단한 데이터베이스 접근
- 자동 매핑으로 코드 간소화
- SQL과 Java 코드의 완전한 분리
- 예외 처리 자동화
Mapper XML 파일 분석
MyBatis Mapper XML 구조
<!-- SELECT 쿼리 -->
<select id="loginMember" parameterType="hashmap" resultMap="memberResultMap">
SELECT MEMBER_NO,
MEMBER_ID,
MEMBER_PWD,
MEMBER_NAME,
PHONE,
EMAIL,
ADDRESS,
INTEREST,
ENROLL_DATE,
MODIFY_DATE,
STATUS
FROM MEMBER
WHERE MEMBER_ID = #{memberId}
AND MEMBER_PWD = #{memberPwd}
AND STATUS = 'Y'
</select>
<!-- UPDATE 쿼리 -->
<update id="updateMemberPwd" parameterType="hashmap">
UPDATE MEMBER
SET MEMBER_PWD = #{updatePwd}
WHERE MEMBER_ID = #{memberId}
</update>
<!-- INSERT 쿼리 -->
<insert id="insertMember" parameterType="Member">
INSERT INTO MEMBER
(
MEMBER_NO,
MEMBER_ID,
MEMBER_PWD,
MEMBER_NAME,
PHONE,
EMAIL,
ADDRESS,
INTEREST
)
VALUES(
SEQ_MNO.NEXTVAL,
#{memberId},
#{memberPwd},
#{memberName},
#{phone},
#{email},
#{address},
#{interest}
)
</insert>
Service 계층 비교
JDBC 방식의 Service
public class MemberService {
public Member loginMember(String userId, String userPwd) {
Connection conn = JDBCTemplate.getConnection();
Member m = new MemberDao().loginMember(userId, userPwd, conn);
if(m != null) {
JDBCTemplate.commit(conn);
} else {
JDBCTemplate.rollback(conn);
}
JDBCTemplate.close(conn);
return m;
}
}
MyBatis 방식의 Service
public class MemberService {
private MemberDao memberDao = new MemberDao();
public Member loginMember(String userId, String userPwd) {
SqlSession sqlSession = Template.getSqlSession();
Member m = memberDao.loginMember(sqlSession, userId, userPwd);
sqlSession.close();
return m;
}
public int updateMemberPwd(String memberId, String updatePwd) {
SqlSession sqlSession = Template.getSqlSession();
int result = memberDao.updateMemberPwd(sqlSession, memberId, updatePwd);
if(result > 0) {
sqlSession.commit();
} else {
sqlSession.rollback();
}
sqlSession.close();
return result;
}
}
핵심 차이점 분석
코드 복잡도 비교
| 구분 |
JDBC 방식 |
MyBatis 방식 |
| 코드 라인 수 |
50+ 라인 |
10-15 라인 |
| 예외 처리 |
수동 처리 |
자동 처리 |
| Connection 관리 |
수동 관리 |
자동 관리 |
| SQL 분리 |
Properties 파일 |
XML 파일 |
유지보수성 비교
JDBC 방식의 문제점
- SQL 변경 시 Java 코드 수정 필요
- 예외 처리 코드 중복
- Connection 관리 복잡
MyBatis 방식의 장점
- SQL과 Java 코드 완전 분리
- 자동 매핑으로 개발 생산성 향상
- 설정 기반으로 유연한 구조
MyBatis 설정 파일
mybatis-config.xml
<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="C##jsp"/>
<property name="password" value="jsp"/>
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="/mappers/member-mapper.xml"/>
</mappers>
Template 클래스 분석
MyBatis SqlSession 관리
package com.kh.mybatis.common;
import java.io.InputStream;
import java.io.IOException;
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 Template {
public static SqlSession getSqlSession() {
String resource = "/mybatis-config.xml";
SqlSession session = null;
try {
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
session = sqlSessionFactory.openSession(false); // false : 수동 커밋
} catch (IOException e) {
e.printStackTrace();
}
return session;
}
}
Template 클래스의 역할
- SqlSessionFactory 생성
- SqlSession 인스턴스 제공
- 설정 파일 로드 및 관리
페이징 처리 비교
MyBatis의 RowBounds 활용
public ArrayList<Board> selectAllBoard(SqlSession sqlSession, PageInfo pi) {
// MyBatis에서 제공하는 페이징 처리
int offset = (pi.getCurrentPage() - 1) * pi.getBoardLimit();
RowBounds rowBounds = new RowBounds(offset, pi.getBoardLimit());
ArrayList<Board> list = (ArrayList)sqlSession.selectList("BoardMapper.selectAllBoard", null, rowBounds);
return list;
}
MyBatis 페이징의 장점
- RowBounds를 통한 간단한 페이징
- SQL 수정 없이 페이징 처리
- 메모리 효율적인 데이터 처리
정리 및 요약
MyBatis의 핵심 장점
- 코드 간소화: JDBC의 복잡한 코드를 간단하게 처리
- SQL 분리: XML 파일을 통한 SQL과 Java 코드 분리
- 자동 매핑: ResultSet을 객체로 자동 변환
- 유지보수성: 설정 기반의 유연한 구조