본문 바로가기
이직&취업/Spring Framework

JPA vs MyBatis: 차이점

by journeylabs 2025. 5. 3.
728x90
반응형

목차

     

    Java 기반 웹 애플리케이션에서 데이터베이스 작업은 필수적이며, 이를 효율적으로 처리하기 위해 JPAMyBatis가 널리 사용됩니다. 둘은 데이터베이스 액세스 방식에서 근본적으로 다른 접근법을 제공합니다. 이 글에서는 JPA와 MyBatis의 주요 개념, 특징과 차이점, 원리 및 구조, 설정 방식, 실무 활용 사례, 그리고 장단점을 초보자부터 실무 개발자까지 이해하기 쉽게 설명합니다.


    1. JPA와 MyBatis란?

    1.1 주요 개념 및 용어

    JPA (Java Persistence API)

    JPA는 Java의 표준 ORM(Object-Relational Mapping) 기술로, 객체와 관계형 데이터베이스 간의 매핑을 처리합니다. JPA는 스펙이며, Hibernate, EclipseLink 같은 구현체를 통해 동작합니다. Spring Data JPA는 JPA를 Spring 프레임워크에 최적화한 모듈입니다.

     

    주요 용어:

    • Entity: 데이터베이스 테이블과 매핑되는 Java 클래스.
    • Repository: 데이터베이스 작업을 위한 인터페이스(CRUD 제공).
    • EntityManager: 엔티티의 생명주기를 관리.
    • JPQL: 객체 지향 쿼리 언어.

    MyBatis

    MyBatis는 SQL 매핑 프레임워크로, 개발자가 직접 SQL 쿼리를 작성하여 데이터베이스와 Java 객체를 매핑합니다. ORM보다는 SQL 중심 접근 방식을 취하며, SQL에 대한 세밀한 제어를 제공합니다.

     

    주요 용어:

    • Mapper: SQL 쿼리와 Java 메서드를 매핑하는 XML 또는 인터페이스.
    • SqlSession: 데이터베이스 작업을 실행하는 세션.
    • ResultMap: 쿼리 결과를 Java 객체에 매핑.
    구분 JPA (Java Persistence API) MyBatis
    개념 ORM(Object-Relational Mapping) 기반 표준 인터페이스 SQL Mapper 프레임워크
    역할 객체와 DB 테이블을 매핑하여 자동 처리 SQL 작성 및 매핑을 직접 제어
    사용법 Entity 클래스 기반으로 자동 CRUD Mapper(XML/Annotation)로 SQL 직접 작성

    1.2 특징

    JPA 특징

    • 객체 중심: 엔티티 객체를 중심으로 데이터베이스 작업을 처리.
    • 자동화: CRUD 메서드 자동 생성, 쿼리 생성 기능 제공.
    • 캐싱: 1차/2차 캐시로 성능 최적화.
    • 표준화: JPA 스펙 기반으로 구현체 변경 가능.

    MyBatis 특징

    • SQL 중심: 개발자가 직접 SQL 쿼리 작성.
    • 유연성: 복잡한 쿼리와 데이터베이스별 최적화 가능.
    • 경량화: ORM의 복잡한 기능 없이 간단한 매핑 제공.
    • 명시적: SQL과 매핑이 명확히 분리.
    항목 JPA MyBatis
    SQL 작성 거의 필요 없음 (자동 생성) 직접 작성 필요 (세밀한 제어)
    생산성 높음 (개발 속도 빠름) 복잡한 쿼리 작성 쉬움
    유지보수성 엔티티 중심으로 높음 SQL 변경 시 직접 수정
    성능 최적화 난이도 있음 (N+1 문제 등 주의) 쿼리 최적화 용이
    러닝커브 다소 높음 (초반 이해 필요) 비교적 쉬움 (SQL 중심)
    대규모 시스템 복잡한 비즈니스 로직과 매핑 가능 초정밀한 SQL 제어 가능

    1.3 JPA vs MyBatis 차이점

    항목  JPA  MyBatis
    기술 유형 ORM (객체-관계 매핑) SQL 매핑 프레임워크
    쿼리 작성 자동 생성, JPQL, @Query로 커스텀 개발자가 직접 SQL 작성
    설정 복잡도 엔티티 매핑 및 설정 필요 XML 또는 어노테이션으로 간단한 매핑
    성능 캐싱 및 자동화로 기본 성능 우수, 복잡한 쿼리에서 비효율적 가능 SQL 최적화로 고성능, 캐싱은 별도 구현 필요
    학습 곡선 ORM 개념과 Hibernate 이해 필요 SQL에 익숙하면 학습 쉬움
    사용 사례 객체 중심, 복잡한 엔터프라이즈 애플리케이션 SQL 중심, 성능 최적화 필요한 프로젝트

    2. 원리 및 구조 상세 설명

    2.1 JPA의 원리와 구조

    JPA는 EntityManager를 통해 엔티티와 데이터베이스 간의 매핑을 관리합니다. Spring Data JPA는 Repository 인터페이스를 통해 CRUD 작업을 자동화하며, Hibernate가 JPA 구현체로 동작합니다.

     

    동작 흐름:

    • @Entity로 정의된 클래스가 테이블과 매핑.
    • Repository 인터페이스에서 메서드 정의 시 Spring Data JPA가 프록시 객체 생성.
    • EntityManager가 트랜잭션 내에서 쿼리 실행 및 캐싱 관리.
    • Spring Boot의 자동 설정으로 데이터소스와 JPA 설정 간소화.

    JPA 코드 예제:

    // 엔티티 클래스
    import jakarta.persistence.Entity;
    import jakarta.persistence.Id;
    import jakarta.persistence.GeneratedValue;
    import jakarta.persistence.GenerationType;
    
    @Entity
    public class User {
        @Id
        @GeneratedValue(strategy = GenerationType.IDENTITY)
        private Long id;
        private String name;
        private String email;
    
        // Getters, Setters
    }
    
    // Repository 인터페이스
    import org.springframework.data.jpa.repository.JpaRepository;
    import org.springframework.data.jpa.repository.Query;
    
    public interface UserRepository extends JpaRepository<User, Long> {
        User findByEmail(String email);
        @Query("SELECT u FROM User u WHERE u.name LIKE %:name%")
        List<User> findByNameContaining(@Param("name") String name);
    }
    

    2.2 MyBatis의 원리와 구조

    MyBatis는 SqlSession을 통해 SQL 쿼리와 Java 객체를 매핑합니다. 개발자가 XML 또는 어노테이션으로 매퍼를 정의하면, MyBatis가 쿼리를 실행하고 결과를 객체로 변환합니다.

     

    동작 흐름:

    1. Mapper XML 또는 인터페이스에서 SQL 쿼리 정의.
    2. SqlSessionFactory가 데이터소스와 매퍼를 초기화.
    3. SqlSession이 쿼리를 실행하고 결과를 매핑.
    4. Spring Boot의 @Mapper와 자동 설정으로 간소화.

    MyBatis 코드 예제:

    // Mapper 인터페이스
    import org.apache.ibatis.annotations.Mapper;
    import org.apache.ibatis.annotations.Select;
    
    @Mapper
    public interface UserMapper {
        @Select("SELECT * FROM users WHERE email = #{email}")
        User findByEmail(String email);
    
        @Select("SELECT * FROM users WHERE name LIKE '%' || #{name} || '%'")
        List<User> findByNameContaining(String name);
    }
    

     

    Mapper XML (선택적):

    <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
    <mapper namespace="com.example.UserMapper">
        <select id="findByEmail" resultType="com.example.User">
            SELECT * FROM users WHERE email = #{email}
        </select>
    </mapper>

    3. 설정 방식

    3.1 JPA 설정

    Spring Boot에서 JPA는 application.yml에 데이터소스와 JPA 설정을 정의합니다.

     

    application.yml:

    spring:
      datasource:
        url: jdbc:mysql://localhost:3306/mydb
        username: root
        password: ${DB_PASSWORD}
        driver-class-name: com.mysql.cj.jdbc.Driver
      jpa:
        hibernate:
          ddl-auto: update
        show-sql: true
        properties:
          hibernate:
            dialect: org.hibernate.dialect.MySQLDialect
    

     

    프로파일 분리:

    spring:
      profiles:
        active: dev
    ---
    spring:
      config:
        activate:
          on-profile: dev
      datasource:
        url: jdbc:h2:mem:testdb
    ---
    spring:
      config:
        activate:
          on-profile: prod
      datasource:
        url: jdbc:mysql://prod-db:3306/mydb
    

     

    환경 변수:

    spring:
      datasource:
        password: ${DB_PASSWORD:default}
    

    3.2 MyBatis 설정

    MyBatis는 데이터소스와 매퍼 설정을 정의합니다.

     

    application.yml:

    spring:
      datasource:
        url: jdbc:mysql://localhost:3306/mydb
        username: root
        password: ${DB_PASSWORD}
        driver-class-name: com.mysql.cj.jdbc.Driver
    mybatis:
      mapper-locations: classpath:mappers/*.xml
      type-aliases-package: com.example.domain
      configuration:
        map-underscore-to-camel-case: true
    
    • mybatis.mapper-locations: Mapper XML 파일 경로.
    • mybatis.type-aliases-package: 엔티티 클래스의 패키지.
    • mybatis.configuration.map-underscore-to-camel-case: DB 컬럼(user_name)을 Java 필드(userName)로 자동 매핑.

    프로파일 분리:

    spring:
      profiles:
        active: dev
    ---
    spring:
      config:
        activate:
          on-profile: dev
      datasource:
        url: jdbc:h2:mem:testdb
    ---
    spring:
      config:
        activate:
          on-profile: prod
      datasource:
        url: jdbc:mysql://prod-db:3306/mydb
    

     

    환경 변수:

    spring:
      datasource:
        password: ${DB_PASSWORD:default}
    

    4. 실무에서의 활용 사례

    4.1 JPA 활용 사례

    • 전자상거래 플랫폼: Spring Data JPA로 사용자, 상품, 주문 엔티티 관리. 예: OrderRepository로 주문 상태별 조회.
    • 마이크로서비스: 각 서비스에서 독립적인 데이터베이스 작업. 예: 사용자 서비스의 UserRepository로 CRUD 처리.
    • 복잡한 트랜잭션: 금융 시스템에서 @Transactional과 함께 복잡한 트랜잭션 관리.
    • 페이징 처리: 대시보드 애플리케이션에서 Pageable로 대량 데이터 표시.

    실제 코드 예제 (JPA 페이징):

    @RestController
    @RequestMapping("/api/users")
    public class UserController {
        private final UserRepository userRepository;
    
        public UserController(UserRepository userRepository) {
            this.userRepository = userRepository;
        }
    
        @GetMapping
        public Page<User> getUsers(Pageable pageable) {
            return userRepository.findAll(pageable);
        }
    }

    4.2 MyBatis 활용 사례

    • 레거시 시스템 통합: 기존 데이터베이스와 복잡한 SQL 쿼리 통합. 예: 금융 보고서 생성.
    • 고성능 쿼리: 대량 데이터 조회에서 최적화된 SQL 작성. 예: 분석 대시보드의 복잡한 조인 쿼리.
    • 다중 데이터베이스: MyBatis의 유연성을 활용해 MySQL과 Oracle 동시 지원.
    • 배치 처리: 대량 데이터 삽입/업데이트에서 SQL 직접 제어.

    실제 코드 예제 (MyBatis 쿼리):

    @Mapper
    public interface UserMapper {
        @Select("SELECT * FROM users WHERE status = #{status} ORDER BY created_at DESC LIMIT #{limit} OFFSET #{offset}")
        List<User> findByStatus(@Param("status") String status, @Param("limit") int limit, @Param("offset") int offset);
    }

    5. 주의사항: 장점과 단점

    5.1 JPA

    장점:

    • 생산성: 자동화된 CRUD와 쿼리 생성으로 boilerplate 코드 감소.
    • 유지보수: 객체 중심 설계로 코드 가독성 및 확장성 향상.
    • 캐싱: 1차/2차 캐시로 성능 최적화.
    • Spring 통합: Spring Boot와의 자동 설정으로 빠른 개발.

    단점:

    • 성능: 복잡한 쿼리에서 Hibernate의 자동 쿼리가 비효율적일 수 있음.
    • 학습 곡선: ORM 개념과 Hibernate 내부 동작 이해 필요.
    • N+1 문제: 연관 관계 처리 시 성능 문제 발생 가능.
    • 과도한 추상화: 내부 로직이 숨겨져 디버깅 어려움.

    주의사항:

    • N+1 문제: @EntityGraph 또는 fetch join으로 최적화.
    • 트랜잭션 관리: @Transactional로 데이터 일관성 유지.
    • 쿼리 최적화: 복잡한 쿼리는 @Query 또는 네이티브 쿼리 사용.

    5.2 MyBatis

    장점:

    • SQL 제어: 개발자가 직접 쿼리 작성으로 성능 최적화 가능.
    • 유연성: 복잡한 쿼리와 데이터베이스별 최적화 쉬움.
    • 경량화: ORM의 복잡한 기능 없이 간단한 매핑.
    • 학습 용이: SQL에 익숙하면 빠르게 적응.

    단점:

    • 보일러플레이트 코드: 반복적인 매핑 작업 필요.
    • 유지보수: SQL과 Java 코드 분리로 변경 시 동기화 주의.
    • 캐싱 부재: 기본 캐싱 없음, 별도 구현 필요.
    • 객체 관리 부족: 엔티티 생명주기 관리 기능 없음.

    주의사항:

    • SQL 인jection: 동적 쿼리 작성 시 바인딩 변수 사용.
    • 매퍼 관리: XML과 인터페이스 간 일관성 유지.
    • 대량 데이터: 배치 처리 시 batch 모드 활용.

    6. 결론

    JPA와 MyBatis는 데이터베이스 액세스 방식에서 서로 다른 철학을 제공합니다. JPA는 객체 중심의 ORM으로, 생산성과 유지보수성을 높이며 복잡한 엔터프라이즈 애플리케이션에 적합합니다. 반면, MyBatis는 SQL 중심의 유연한 매핑으로, 성능 최적화와 복잡한 쿼리가 필요한 프로젝트에 강점을 보입니다.

    프로젝트의 요구사항에 따라 선택이 달라집니다:

    • 객체 중심, 빠른 개발: JPA (Spring Data JPA) 추천.
    • SQL 최적화, 고성능: MyBatis 추천.
    • 하이브리드: 소규모 프로젝트는 JPA, 성능 최적화 필요한 부분은 MyBatis 사용.

    초보자는 JPA로 ORM 개념을 익히고, 점차 MyBatis로 SQL 제어를 학습하는 경로를 추천합니다. 이 글을 통해 JPA와 MyBatis의 차이와 활용 방법을 명확히 이해했다면, 다음 프로젝트에서 적합한 기술을 선택해 효율적인 데이터베이스 작업을 수행할 수 있을 것입니다!

     

    • CRUD 중심 + 빠른 개발JPA 선택이 유리합니다.
    • 복잡한 조회 쿼리/퍼포먼스 최적화MyBatis 선택이 더 적합합니다.
    • 혼합 사용도 가능: 복잡한 부분만 MyBatis로 빼는 것도 실무에서 자주 사용합니다.

    정답은 없습니다. "서비스 특성"과 "팀 숙련도"에 맞는 선택이 최선입니다.

    728x90
    반응형