JPA vs MyBatis — 언제 무엇을 쓸 것인가
새 프로젝트를 시작하는데 JPA를 쓸지 MyBatis를 쓸지 고민됩니다. 둘 다 써본 입장에서, 어떤 기준으로 선택하면 후회하지 않을까요?
개념 정의
JPA 는 객체와 테이블을 매핑하는 ORM 표준입니다. 엔티티 클래스를 정의하면 SQL을 자동 생성합니다. MyBatis 는 SQL을 직접 작성하고, 그 결과를 객체에 매핑하는 SQL Mapper입니다.
JPA: Entity 클래스 → 자동 SQL 생성 → DB
MyBatis: SQL 직접 작성(XML/어노테이션) → 결과 매핑 → 객체
핵심 차이
| 기준 | JPA (Hibernate) | MyBatis |
|---|---|---|
| SQL 제어 | 자동 생성 (JPQL/Querydsl) | 직접 작성 (XML/어노테이션) |
| 학습 곡선 | 높음 (영속성 컨텍스트, 프록시, N+1) | 낮음 (SQL 알면 바로 시작) |
| 복잡한 쿼리 | Querydsl 필요, 한계 있음 | 네이티브 SQL 자유롭게 |
| 객체 매핑 | 자동 (연관관계, 상속, 프록시) | 수동 (ResultMap) |
| 변경 감지 | Dirty Checking 자동 | 직접 UPDATE SQL 작성 |
| 캐싱 | 1차/2차 캐시 내장 | 직접 구현 또는 없음 |
| 성능 튜닝 | 추상화 뒤에 숨어서 어려움 | SQL이 보여서 직관적 |
| 테이블 변경 | 엔티티만 수정하면 됨 | SQL도 함께 수정해야 함 |
JPA가 강한 영역
-
도메인 모델이 복잡한 경우 — 연관관계가 많고, 객체 그래프 탐색이 잦은 서비스. JPA의 자동 매핑과 지연 로딩이 생산성을 높입니다.
-
CRUD 중심 애플리케이션 — 기본적인 저장/조회/수정/삭제가 대부분이면 Spring Data JPA의 Repository 인터페이스만으로 충분합니다.
-
** 스키마 변경이 잦은 초기 개발** — 엔티티 클래스만 수정하면 되므로, SQL을 일일이 고칠 필요 없습니다.
MyBatis가 강한 영역
-
** 복잡한 쿼리가 많은 경우** — 통계, 리포트, 다중 조인, 서브쿼리 등. SQL을 직접 작성하는 게 빠르고 정확합니다.
-
** 레거시 DB와 연동** — 테이블 구조가 엔티티로 깔끔하게 매핑되지 않는 경우. 정규화가 안 된 테이블, 복합 키, 뷰 테이블.
-
SQL 튜닝이 중요한 서비스 — 실행 계획을 직접 보면서 인덱스 힌트를 주거나, DB 특화 문법을 써야 하는 경우.
선택 기준 플로차트
실무에서의 현실적 선택
대부분의 프로젝트에서는 ** 둘 중 하나만 쓰지 않습니다 **.
// 기본 CRUD — JPA
@Repository
public interface OrderRepository extends JpaRepository<Order, Long> {}
// 복잡한 통계 쿼리 — 네이티브 SQL 또는 MyBatis
@Query(value = "SELECT ... 복잡한 통계 ...", nativeQuery = true)
List<OrderStats> findMonthlyStats(@Param("year") int year);
JPA를 기본으로 쓰되, JPA로 표현하기 어려운 복잡한 쿼리만 네이티브 SQL 또는 MyBatis로 처리하는 조합이 가장 실용적입니다.
함정 — 이걸 모르면 터진다
JPA를 쓰면서 SQL을 모르면 안 된다
JPA가 SQL을 자동 생성해주지만, 생성된 SQL이 효율적인지 판단하려면 SQL을 알아야 합니다. spring.jpa.show-sql=true로 나오는 쿼리를 읽지 못하면 N+1 문제를 발견할 수 없습니다.
MyBatis에서 동적 SQL의 함정
MyBatis의 <if>, <choose>, <foreach> 태그로 동적 SQL을 만들면 조건 조합이 복잡해지면서 ** 예상치 못한 SQL이 생성 **될 수 있습니다. WHERE 절이 비어있거나, AND가 잘못 붙는 경우가 흔합니다.
"MyBatis가 더 빠르다"는 착각
같은 쿼리라면 JPA(Hibernate)와 MyBatis의 성능 차이는 거의 없습니다. 차이가 나는 건 N+1 문제나 불필요한 쿼리 때문이지, 프레임워크 자체의 오버헤드가 아닙니다.
정리
| 상황 | 선택 | 이유 |
|---|---|---|
| 도메인 복잡 + CRUD 중심 | JPA | 자동 매핑, 변경 감지, 생산성 |
| 복잡한 쿼리 + 레거시 DB | MyBatis | SQL 직접 제어, DB 특화 문법 |
| 둘 다 필요 | JPA + 네이티브 SQL | 기본은 JPA, 예외만 SQL |
| SQL 실력이 강한 팀 | MyBatis | 학습 곡선 없이 바로 생산성 |
| 빠른 프로토타이핑 | JPA | 스키마 변경에 유연 |