
Spring과 Spring Boot를 공부하다 보면 누구나 한 번쯤은 MyBatis와 JPA 중 무엇을 선택할지 고민하게 된다.
나 역시 처음에는 MyBatis를 사용해 직접 SQL을 작성하며 장단점을 몸소 느껴보았다.
그 후 JPA를 접했을 때는 “복잡한 쿼리는 결국 직접 작성해야 하는데, 그렇다면 차라리 MyBatis를 쓰는 게 낫지 않을까?” 라는 의문도 들었다.
하지만 실제로 사용해보니, JPA는 객체와 데이터베이스를 자동으로 매핑해주고 반복적인 CRUD 코드를 줄여주어 생산성을 높이는 장점이 있었다.
결국, MyBatis와 JPA는 각기 다른 장단점을 가진 도구이며, 프로젝트 상황과 팀의 선호도에 따라 선택할 수 있다는 점을 깨닫게 되었다.
위 두 기술의 기본적인 개념은 아래와 같다.
MyBatis : SQL 중심의 SQL Mapper 프레임워크.
JPA : Entity <-> DB 매핑 기능을 하는 ORM 표준 명세이며, 구현체로는 Hibernate, EclipseLink 등 사용.
간단한 개념만으로는 이 기술들의 차이가 쉽게 와닿지 않을 수 있다. 만약 누군가가 “MyBatis와 JPA가 뭐예요?”라고 묻는다면 막상 설명하려다 “어... 그러니까...” 하며 말문이 막힐지도 모른다. 그래서 초등학생도 알 수 있는 설명과 함께 구체적인 특징, 장단점을 다루고자 한다.
MyBatis
여기에 MyBatis 식당이 있다.
MyBatis 식당은 손님이 원하는 레시피를 직접 써서 요리사에게 주문하는 시스템이다.
즉, 손님은 “이 재료(=테이블/컬럼)를 써서, 이렇게 조리(=조건, JOIN 등)해줘”라고 세세하게 적어준다.
그래서 음식의 맛(=DB 성능)까지 세밀하게 조절할 수 있지만,
요리사가 항상 레시피대로 일일이 만들어야 하므로 일이 많아진다.
MyBatis는 XML이나 Annotation을 활용하여 직접 작성한 SQL과 객체를 매핑한다.
<mapper namespace="com.example.mapper.UserMapper">
<!-- id: 메서드 이름, resultType: 결과를 매핑할 객체 -->
<select id="findById" parameterType="int" resultType="com.example.domain.User">
SELECT id, name, email
FROM users
WHERE id = #{id}
</select>
</mapper>
import org.apache.ibatis.annotations.Select;
public interface UserMapper {
@Select("SELECT id, name, email FROM users WHERE id = #{id}")
User findById(int id);
}
👍 세밀한 SQL 제어(동적 SQL)로 복잡한 쿼리(JOIN, WHERE 등) 작성, 퍼포먼스 최적화 가능
👍 쿼리 튜닝을 통해 성능 최적화 용이
👎 DB 설계 수정 시 매핑, SQL 모두 수정하여 유지보수 부담
👎 간단한 CRUD도 반복적으로 작성해야 함
👎 트랜잭션(commit, rollback), 캐싱 등 직접 구현 필요
JPA ( Java Persistence API )
Java 기반의 ORM 표준 명세로, Hibernate, EclipseLink 등으로 구현
ORM ( Object-Relational Mapping ): 객체 지향 프로그램 + DB 연결
여기에 JPA 식당이 있다.
JPA 식당에서는 손님이 요리 이름만 말하면 된다.
예를 들어 “김치찌개 주세요”라고 하면, 요리사(JPA 구현체)가 알아서 레시피를 찾아내고,
재료를 준비하고, 조리(쿼리 생성)까지 진행한다.
손님은 세세한 과정을 몰라도 쉽게 원하는 요리를 받을 수 있고, 덕분에 빠르고 편리하게 식사가 가능하다.
다만, 아주 특별한 요리(=복잡한 쿼리)가 필요할 때는 요리사가 제대로 못 만들 수도 있어,
그때는 다시 직접 레시피를 써줘야 한다.

@Autowired
private UserRepository userRepository;
public void example() {
// 생성
User user = new User();
user.setId(1L);
user.setName("Alice");
userRepository.save(user);
// 조회
User findUser = userRepository.findById(1L).orElse(null);
// 수정
findUser.setName("Bob");
userRepository.save(findUser);
// 삭제
userRepository.delete(findUser);
}
👍 CRUD 코드 최소화
👍 DB 설계 수정 등 유지보수 용이
👍 추상화된 데이터 접근을 통해 여러 DB 벤더 적용 가능
👍 트랜잭션 자동 처리 가능 ( @Transactional )
👎 복잡한 쿼리 적용 어려움 ( JPQL나 SQL 혼용으로 코드 복잡 )
👎 JOIN, N+1 문제 등 최적화 어려움 ( Fetch 전략, QueryHints 등 필요 )
위와 같이 MyBatis와 JPA를 살펴본 결론은 간단하다.
“우리 프로젝트에 복잡한 쿼리가 필요할까? 팀의 스킬셋과 취향은?”에 따라 자유롭게 선택하면 된다.
복잡한 쿼리와 SQL 제어가 필요하다면 → MyBatis
간단한 매핑과 객체 지향적인 접근이 필요하다면 → JPA
즉, 둘 다 장단점이 있으니 상황과 취향에 맞춰 골라 쓰자.
말하자면, SQL을 직접 요리하고 싶은 사람은 MyBatis,
객체 중심으로 편하게 즐기고 싶은 사람은 JPA, 취향껏 선택하면 끝!