[Spring] DB 기술의 구분, Spring Data JPA의 Hibernate

이지연·2026년 1월 21일

DB 기술의 구분

프로젝트에서 “지금 어떤 데이터 접근 기술을 쓰는지”는 결국 코드에 뭐가 보이냐로 판단하면 된다.
JDBC는 DataSource, MyBatis는 mapper, 순수 JPA는 EntityManager, Spring Data JPA는 JpaRepository 상속이 가장 직관적인 단서다.

1) JDBC: DataSource(또는 JdbcTemplate)가 보이면 거의 확정

JDBC 기반은 DB 연결/쿼리 실행의 흐름이 코드에서 꽤 직접적으로 드러난다.
보통 DataSource로 커넥션을 얻고, SQL을 직접 작성해서 실행하며, 조회 결과를 DTO/엔티티로 조립하는 과정도 수동인 편이다.

2) MyBatis: mapper(인터페이스 + XML/어노테이션)가 보인다

MyBatis는 SQL을 직접 작성하되, 그 SQL을 mapper라는 단위로 분리해 관리하는 스타일이라 “mapper 구조”가 힌트가 된다.
코드에서 xxxMapper 같은 인터페이스가 보이거나, resources/mapper 아래 XML에 SQL이 모여 있으면 MyBatis 가능성이 높다. (설정에도 mapper-locations가 같이 따라오는 경우가 많음)

3) 순수 JPA: EntityManager가 직접 등장한다

순수 JPA는 EntityManager를 직접 주입받아 find, persist, createQuery(JPQL) 같은 API로 데이터 접근을 구현하는 경우가 많다.
이때부터는 테이블 중심이 아니라 “엔티티(객체) 중심”으로 설계/조회가 가능해지고, JPQL 같은 객체지향 쿼리로 조회를 작성한다.

4) Spring Data JPA: JpaRepository 상속하면 끝 (EntityManager는 안 보여도 내부적으로 쓴다)

Spring Data JPA는 JPA 위에서 동작하면서 Repository를 더 쉽게 쓰게 해주는 라이브러리다.
그래서 코드에서 EntityManager가 안 보일 수 있는데, JpaRepository가 내부적으로 EntityManager를 참조해서 메서드들을 구현하는 구조다.

  • 특징
    • save(), findById(), findAll(), delete() 같은 기본 CRUD를 바로 제공한다.
    • findByEmail 같은 “메서드 이름 규칙 기반 쿼리(derived query)”도 선언만 하면 만들어진다. methods.html)
    • Repository 구현체를 직접 안 만들어도, 런타임에 프록시/구현체가 생성되어 동작한다.

비교 표

기술특징
JDBCRaw SQL을 직접 작성하고 실행한다. 커넥션/트랜잭션 처리, 파라미터 바인딩, ResultSet 파싱, 객체 매핑까지 대부분을 개발자가 수동으로 처리한다.
MyBatisSQL은 직접 작성하되, 매퍼(XML/어노테이션)로 파라미터 바인딩과 결과 객체 매핑을 편하게 한다. 쿼리 제어가 명확해서 복잡한 조회에 강하다.
JPAORM 표준 스펙 기반으로 엔티티 중심 개발을 한다. 기본 CRUD는 SQL을 직접 쓰지 않아도 되고, 변경 감지(Dirty Checking) 등으로 DB 반영이 자동화된다.
Spring Data JPAJPA를 더 쉽게 쓰게 해주는 스프링의 추상화 레이어다. JpaRepository 제공, 메서드 이름 기반 쿼리 생성, @Query 지원 등으로 Repository 보일러플레이트를 크게 줄여준다(내부적으로는 JPA/EntityManager를 사용).

JPA와 Hibernate

JPA는 “ORM 표준”이라서 인터페이스/규약(명세)에 가깝고, 실제 동작은 구현체가 맡는다.
Spring에서 흔히 쓰는 구현체가 Hibernate이고, 결국 JPA를 쓴다는 건 내부적으로 Hibernate 같은 Provider가 “엔티티 상태를 추적하고 SQL을 생성해서 실행한다”는 의미다.

  • 결론: JPA는 스펙이고, Hibernate는 구현체다

ORM(Object-Relational Mapping)객체(클래스/엔티티)와 관계형 DB 테이블을 매핑해서, 개발자가 SQL 대신 객체를 다루는 방식으로 데이터를 저장·조회·수정·삭제할 수 있게 해주는 기술이다.


Hibernate가 실제로 해주는 핵심들 (체감되는 기능 위주)

Hibernate(JPA 구현체)가 유용한 이유는 “DB에 반영되는 과정을 자동화”해주는 기능들이 있기 때문이다.

  • 변경 감지(Dirty Checking)
    • 트랜잭션 안에서 엔티티 값을 바꾸면, Hibernate가 변경을 감지해서 커밋 시점에 UPDATE SQL을 만들어 반영한다
  • 영속성 컨텍스트(Persistence Context) 기반 동작
    • 엔티티의 상태를 관리하면서, flush/commit 타이밍에 DB와 동기화한다.
  • 즉, 개발자는 “매번 update 쿼리 직접 작성”이 아니라 “객체 변경”으로 작업이 끝나는 경우가 많아진다.

(+) 트랜잭션은 서비스 계층에서 끊는다

Spring Data JPA든 순수 JPA든, 실제 EntityManager는 트랜잭션 범위 안에서 의미 있게 동작하고(변경 감지/flush 등), 트랜잭션 경계가 곧 commit/rollback 기준이 된다.
그래서 레포지토리 단위가 아니라 “회원 탈퇴 같은 유스케이스 단위(서비스 메서드 단위)”로 트랜잭션을 묶어야 중간 실패 시 전체 rollback이 가능하고 데이터가 일관되게 유지된다.

  • 조금 더 상세한 시나리오는 이전글에서 다루었다.

(+) JPA + Hibernate 설정

  • datasource: “DB에 접속”하기 위한 최소 정보 묶음

    • url: 접속할 DB 주소/포트/스키마(데이터베이스 이름) 지정
    • username / password: DB 인증 정보
    • driver-class-name: 보통 자동 감지되지만, 드라이버를 못 잡는 환경이면 명시
  • jpa: “JPA가 어떤 방식으로 동작할지” 정하는 설정 묶음

    • database / database-platform(dialect): DB 종류/방언 지정 (Hibernate가 생성하는 SQL 호환성에 영향)
    • generate-ddl: 엔티티 기준으로 DDL(테이블 생성/변경) 생성 기능을 사용할지 여부
    • hibernate.ddl-auto: 스키마 자동 처리 전략(개발/운영 환경에 따라 선택)
      • create: 매 실행 시 drop 후 재생성 (초기 개발용, 데이터 유지 안 됨)
      • update: 변경분만 반영 시도 (개발/QA에서 편하지만 예기치 않은 변경 가능)
      • validate: 스키마 변경은 안 하고 매핑만 검증 (운영에서 안전한 편)
      • none: DDL 관련 동작 자체를 하지 않음 (운영 선택지)
    • show-sql / format_sql: 실행 SQL을 출력하고 보기 좋게 포맷 (개발/디버깅용)
    • open-in-view: 요청 처리 끝까지 영속성 컨텍스트를 열어둘지 여부 (보통 서비스 계층 트랜잭션 기준으로 가져가려면 false로 관리)
  • 환경별 ddl-auto 설정 흐름은 이전글에서 다루었다.
spring:
  datasource:
    url: jdbc:mariadb://localhost:3306/test
    username: root
    password: 1234
    # driver-class-name: org.mariadb.jdbc.Driver

  jpa:
    database: mysql
    database-platform: org.hibernate.dialect.MariaDBDialect
    generate-ddl: true

    hibernate:
      ddl-auto: update

    show-sql: true
    properties:
      hibernate:
        format_sql: true

    open-in-view: false
profile
Eazy하게

0개의 댓글