MyBatis
MyBatis는 데이터베이스와 자바 객체 간의 매핑을 쉽게 처리하기 위해 개발된 오픈 소스이며 ORM(Object-Relational Mapping) 프레임워크입니다.
기존의 JDBC(Java Database Connectivity)를 이용한 방식을 간결하고 편리하게 사용할 수 있도록 도와주는 도구입니다.
ORM이란??
ORM은 Object-Relational Mapping 약어로 객체와 관계형 데이터베이스 간의 매핑을 자동화해주는 프로그래밍 기법을 의미합니다.
객체 지향 프로그래밍 언어는 클래스와 객체로 구성된 구조를 가지고 있습니다. ORM은 이 둘 간의 패러다임 불일치를 해결하기 위해 사용됩니다.
MyBatis와 ORM??
ORM은 객체와 관계형 데이터베이스 간의 매핑을 자동화하여 개발자가 직접 SQL을 작성하지 않고도 객체 지향적으로 데이터베이스를 다룰 수 있도록 지원하는 프레임워크입니다.
반면, MyBatis는 Java 언어를 위한 경량화된 SQL Mapper로서 SQL 쿼리와 자바 객체 간의 매핑을 쉽게 처리하기 위해 설계되었습니다.
이로 인해 MyBatis는 객체와 데이터베이스 간의 연결을 명시적으로 다루고 SQL을 직접 작성하는 특징을 가지며
ORM 프레임워크와는 조금 다른 측면을 가지고 있습니다.
JDBC
데이터베이스와 자바 애플리케이션 사이의 연결 및 쿼리 실행을 관리하는 데 사용되는 Java 표준 인터페이스입니다.
순수 JDBC를 사용하여 DB접근하는 방식은 SQL 쿼리를 자바 문자열로 작성해야 하며, SQL과 Java Code를 분리하기 어렵고 번거로운 점이 있습니다.
SQL 쿼리를 자바 문자열로 작성하는 과정
try {
conn = dataSource.getConnection();
//SQL 쿼리를 자바 문자열로 작성
StringBuilder listArticle = new StringBuilder();
listArticle.append("select b.article_no, b.user_id, b.subject, b.content, b.hit, b.register_time, m.user_name \n");
listArticle.append("from board b, members m \n");
listArticle.append("where b.user_id = m.user_id \n");
if(!word.isEmpty()) {
if(key.equals("userid"))
listArticle.append("and b.user_id = ? \n");
else if(key.equals("subject"))
listArticle.append("and b.subject like ? \n");
}
listArticle.append("order by b.article_no desc limit ?, ? \n");
pstmt = conn.prepareStatement(listArticle.toString());
int idx = 0;
if(!word.isEmpty()) {
if(key.equals("userid"))
pstmt.setString(++idx, word);
else if(key.equals("subject"))
pstmt.setString(++idx, "%" + word + "%");
}
pstmt.setInt(++idx, start);
pstmt.setInt(++idx, listsize);
} finally {
dbUtil.close(rs, pstmt, conn);
}
데이터를 꺼내오는 작업도 마찬가지입니다. VO에 직접 매핑하는 과정은 생산성 측면에서 떨어집니다.
또한 매핑 과정에서 데이터베이스 컬럼 명의 오류가 있을 시 컴파일 단계에서 오류를 발생하지 않기 때문에 직접 실행시켰을 때 Exception을 확인해야 한다는 번거로움도 존재합니다.
VO에 직접 매핑하는 과정
// SQL 쿼리 실행
ResultSet rs = null;
rs = pstmt.executeQuery();
// VO
while (rs.next()) {
BoardDto boardDto = new BoardDto();
boardDto.setArticleNo(rs.getInt("article_no"));
boardDto.setUserId(rs.getString("user_id"));
boardDto.setUserName(rs.getString("user_name"));
boardDto.setSubject(rs.getString("subject").replace("<", "<"));
boardDto.setContent(rs.getString("content").replace("\n", "<br/>"));
boardDto.setHit(rs.getInt("hit"));
boardDto.setRegisterTime(rs.getString("register_time"));
list.add(boardDto);
}
return list;
또한 커넥션 관리 및 리소스 해제와 같은 작업들을 직접 처리해야 하는 번거로움도 존재합니다.
리소스 해제 과정
// finally 구문을 통해 리소스 해제를 직접 처리해주어야 한다.
finally {
dbUtil.close(rs, pstmt, conn);
}
// DBUtil.java
public void close(AutoCloseable... closeables) {
for (AutoCloseable c : closeables) {
if (c != null) {
try {
c.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
이런 문제점들을 해결하고자 나타난 것이 바로 MyBatis입니다.
MyBatis를 사용하면 XML 또는 어노테이션을 활용하여 SQL 쿼리와 자바 코드를 분리하여 작성할 수 있습니다. 또한 데이터베이스 커넥션 관리를 자동화합니다.
[ 생산성 측면에서 이점 ]
생산성은 코드 양이 줄거나 같은 개발을 하는데 시간이 단축된다는 의미입니다.
위에서 코드로 설명했던 것 처럼 DB에서 가져온 데이터를 vo 객체에 직접 매핑하면 코드 몇 줄이 될지 상상해보시면 이해가 갈 수 있습니다.
[ 커넥션 관리 자동화 ]
MyBatis는 데이터베이스 커넥션 관리를 외부 Connection Pool 라이브러리(예: Apache Commons DBCP, HikariCP, c3p0 등)에 위임합니다. 이렇게 함으로써 MyBatis는 데이터베이스 커넥션 풀링을 전적으로 외부 라이브러리에 의존하여 커넥션 관리를 수행합니다.
MyBatis에서 데이터베이스 커넥션 관리를 효율적으로 수행하고, 개발자는 커넥션 관리에 신경 쓰지 않고 데이터베이스에 집중할 수 있게 됩니다.
DBCP (DataBase Connection Pool)
WAS에 DataBase 접속 정보를 저장하고 메서드에서 커넥션 정보를 가져다가 사용하는 방법입니다. 데이터베이스와의 연결은 시간과 자원을 많이 소모하기 때문에 CP(Connection Pool)을 이용하여 미리 연결을 생성하고 재 사용함으로써 애플리케이션의 성능을 향상시킵니다.
MyBatis를 사용한 프로젝트에서 Model 객체의 코드를 살펴보며 기존의 JDBC 방식과 어떤 변화가 있는지 살펴보도록 하겠습니다.
BoardMapper Class (DAO)
@Repository
public interface BoardMapper {
public int writeBoard(BoardDTO boardDto);
public List<BoardDTO> selectList(@Param("start") int startRow, @Param("cnt") int count, @Param(value = "gugun") String gugun);
public BoardDTO selectOne(int bno);
public int modifyBoard(BoardDTO boardDto);
public int deleteBoard(int bno);
}
그렇다면 현업에서는 JPA말고 왜 Mybatis를 사용할까?
현업에서 JPA 대신 MyBatis를 사용하는 이유
[ 러닝 커브 ]
JPA는 Mybatis에 비해 러닝 커브가 높은 편입니다.
Mybatis의 경우는 기존의 JDBC를 이용한 개발 방식에서 SQL 쿼리를 통한 접근방식을 따로 모아서 관리하는 것이기 때문에 JDBC를 이용한 개발을 할 줄 아는 개발자라면 쉽게 배울 수 있습니다.
하지만 JPA는 SQL Query를 직접 만들어준다는 장점이 있지만, 영속성 컨텍스트, Entity 매핑 등 복잡한 개념때문에 러닝커브가 높습니다.
[ 세밀한 SQL 제어 ]
MyBatis는 일반적으로 JPA와 비교하여 좀 더 세밀한 SQL 제어가 필요하거나, 기존에 이미 존재하는 SQL 쿼리들을 재사용해야 할 때 많이 사용됩니다. 또한 SQL 작성에 익숙한 개발자들이나 특정 데이터베이스 기능을 활용해야 하는 경우에도 MyBatis를 선호할 수 있습니다.
JPA와 MyBatis의 선택
상황에 맞게 사용하자!
- 추가, 수정, 삭제, 테이블 한 개의 조회는 JPA와 같은 ORM을 사용하면 편리합니다.
- 두 개 이상의 테이블을 조인할 경우 Mybatis로 쿼리를 작성하는게 편리합니다.
또한 JPA에서는 서브쿼리(인라인 뷰)는 JPQL(Querydsl 포함)에서 지원하지 않습니다. 그래서 이러한 문제점이나 복잡한 쿼리는 Mybatis를 함께 사용해서 처리한다면 된다고 합니다.
그래서 결론은, 어느 한쪽을 고집하는 것 보다는 상황에 맞게 사용하는게 적절하다고 생각합니다.
https://www.inflearn.com/questions/25491/from%EC%A0%88-%EC%84%9C%EB%B8%8C-%EC%BF%BC%EB%A6%AC