정상혁님이 쓰신 글 Java에서 XML없이 SQL개발하기 을 보고 Mybatis 를 버려야겠다는 생각을 했다.
정상혁님의 글 내용중에도 있지만, 현재 Mybatis 를 썼을 때 발생하는 장점이 많이 퇴색했다.
Mybatis 는 조인된 결과를 담는 ResultMap 과 내부에서 쓰는 Association 같은 것을이 너무 불편했고,
쿼리에선 값이 정상적으로 조회되는데 Mybatis 결과가 객체에 정상적으로 셋팅되지 않을때, 이유를 알기 어렵고,
쿼리 결과를 개발자가 직접 핸들링 하기가 힘들다.
또한 Mybatis 에서 제공되는 기법들은 Spring JDBC에서도 모두 제공되고 있다.
그런데, 국내에서는 Mybatis 가 거의 관례처럼 돼버렸다.
요즘은 그래도 김영한 ORM 전도사님께서 국내최초로 ORM 책을 내주시고, 인터넷에도 제법 많은 발표 자료가 있어서 공부하기가 수월해졌다.
JPA/ORM 을 썼을 때 무엇이 좋은지 알고 싶으면 김영한님이 올리신 자료를 보면 확실히 알 수 있다.
http://devon.daum.net/2012/session/b4#.VcFXJvntlZ3
김영한님이 올리신 자료 중 발췌
관련하여 토비의 스프링의 저자이신 이일민님께서는 Facebook 에 이런 글을 올리셨다.
"JPA/ORM이 왜 필요한지, 어떤 문제를 해결해주는지, 왜 전세계 개발자들이 대부분 JPA를 사용하고 있는지, 스프링은 왜 최근까지 JPA/하이버네이트는 버전별로 빠짐없이 지원하면서 MyBatis에는 조금도 관심없는 이유가 뭔지 알고 싶다면 이 발표를 보면 된다.
그리고 나서 JPA를 한 번 써보고 싶다, 제대로 공부하고 싶다는 마음이 들면 이 세션의 발표자인 Younghan Kim이 쓴http://www.yes24.com/24/goods/19040233 를 구해서 차근차근 읽고 실습해보면 된다. 이 발표를 다 봤어도 JPA 필요성에 대해 의문이 남는다면, 혹은 주변에서 들은 JPA는 이런저런 단점이 많아서 실전에는 적합하지 않다는 유언비어가 떠올라 마음이 내키지 않는다면 어서 빨리http://www.yes24.com/24/goods/19040233 를 읽어보자. JPA의 진정한 매력이 무엇인지 확실하게 알게 될 것이다. " - 이하 생략
다시 본론으로 돌아와서,
처음에는 Data Access 기술로 JPA / HIBERNATE 를 선택하고 싶었다.
하지만, 다른 개발자분들의 우려가 컸고, 본인 스스로도 사실 예전에 공부하고 개인프로젝트에 적용해본게 전부였기때문에 확신하지 못했다.
차선책으로 Mybatis 를 버리고 Spring JDBC 를 선택했는데, 그것도 우려가 컸다..
Mybatis 를 버리고 Sprnig JDBC 를 선택했을 때,
가장 큰 문제는
쿼리 작성을 자바 내에서 해야한다는 것이다.
자바에서는 멀티라인 스트링을 지원하지 않기 때문에 쿼리를 보관하기 위해서는,
StringBuilder 로 append 하거나, Stiring 으로 + 이어붙이기를 해야한다.
이렇게 되면 소스도 장황해지고 가독성도 너무 안좋고, 쿼리 작성하기도, 수정하기도 불편하다.
정상혁님의 글을 보고 선택하게 된 것이 GROOVY 의 멀티라인스트링 """ 이다.
GROOVY 는 JVM위에서 돌아가고 자바의 클래스와 문법을 그대로 쓸 수 있고, 멀티라인 스트링 까지 지원하니 더할나위 없는 선택이였다.
또, Spring JDBC 의 NamedJdbcTemplate 은 쿼리내 :파라미터명 형태로 Named Parameter 를 넣을 수 있기 때문에 Mybatis 의 #변수명# 형태와 동일하게 사용할 수 있다.
update post set delete_flag = TRUE where post_key = :postKey
다이나믹 쿼리를 사용할 때
Mybatis 같은 경우 Mybatis 전용 다이나믹 xml 문법을 익혀야하고,
장황해지며, 컨트롤하기 어렵다.
Spring JDBC 를 사용하면 개발자에게 가장 익숙한 if, for 문 등으로 다이나믹 쿼리를 작성할 수 있다.
그리고 Java 8 의 람다를 이용하면 RowMapper 를 아래와 같은 형태로 간결하게 작성할 수 있다.
@Override
public List<Post> selectTimelineByPostKey(List<Long> postKeyList) {
Map<String, List<Long>> param = Collections.singletonMap("postKeyList", postKeyList);
return this.jdbcTemplate.query(
PostSqlMap.selectTimelineByPostKey(postKeyList),
param,
this::postMapRow);
}
위 예에서 리스트가 담긴 맵을 넘기면
WHERE a.post_key IN
(:postKeyList)
이런 형태로 사용할 수 있다.. Mybatis 의 iterator 나 foreach 보다 훨씬 편하다
또 자바8의 Optional 을 이용하여
usersOrg.setUpdDate(
Optional.ofNullable(rs.getTimestamp("rank_upd_date"))
.map(Timestamp::toLocalDateTime).get());
이러한 형태로 널 체크 및 메소드레퍼런스를 이용하여 결과값에 특정 메소드 적용이 쉬워졌다.
위 예에서는 쿼리 결과를 타임스탬프 형태로 받아서 자바8의 LocalDateTime 으로 변환하는 일을 수행하고 있다.
Mybatis 를 버리고 Spring JDBC를 선택했을 때, 우려섞인 목소리가 나왔을 때
위와 같은 내용으로 여러 개발자분을 설득에 성공하였고,
현재까지는 모든 개발자분이 매우 만족스럽게 개발중이다.