ORM과 SQL Mapper - Hibernate, JPA

2025. 3. 9. 12:37·Back-end

ORM과 SQL Mapper - Hibernate, JPA

ORM

ORM이란?

객체와 RDB 테이블을 매핑시켜 객체와 관계형 모델의 불일치 문제를 해결하고 RDB 테이블을 객체 지향적으로 사용하게 해주는 기술
객체 필드 <-(Mapping)-> 테이블 데이터

 

객체와 DB가 연결되어 있기 때문에 개발자가 직접 쿼리를 작성하지 않아도 표준 인터페이스를 기반으로 처리를 할 수 있다.

ORM 장단점

  • 장점
    • 쿼리 작성 없이 메서드를 통해 객체 중심으로 DB를 조작할 수 있다.
    • ORM이 DB 스키마 변경을 자동으로 처리해 주기 때문에 개발자는 Java 코드에 더 집중할 수 있다.
  • 단점
    • 세밀한 제어가 힘들기 때문에 복잡한 쿼리는 직접 QueryDSL을 통해 작성해야 한다.
    • 성능 문제가 발생할 수 있다.
      • JPA N+1 문제 등
JPA N+1 문제

게시글을 조회할 때 연관된 댓글도 함께 조회하는 쿼리를 생각해보자

-- 이상적인 쿼리 (게시글 ID가 1인 게시글과 댓글을 함께 가져옴)
SELECT *
FROM board b
LEFT JOIN comment c ON b.board_id = c.board_id
WHERE b.board_id = 1;

위처럼 한 쿼리로 게시글과 관련 댓글을 가져올 수 있지만 JPA를 사용하면 다음과 같이 댓글 개수(N개)의 쿼리가 추가로 생성되는 문제가 있다.
즉, 한 번에 가져올 수 있는 댓글을 댓글의 개수 만큼큼 쿼리를 발생 시켜 성능 저하를 발생시키는 문제를 말한다.

-- 게시글 조회 쿼리
SELECT * FROM board WHERE board_id = 1;

-- 댓글 조회 쿼리 (N번 실행)
SELECT * FROM comment WHERE board_id = 1;  -- 첫 번째 댓글
SELECT * FROM comment WHERE board_id = 1;  -- 두 번째 댓글
...
SELECT * FROM comment WHERE board_id = 1;  -- N 번째 댓글

Hibernate - Spring Data JPA

Java에 대표적인 ORM 프레임워크로는 Hibernate가 있다.

Hibernate란

JPA는 규칙을 정의한 표준 인터페이스이고 Hibernate는 JPA가 정의한 규칙에 맞게 구현한 구현체이다.
즉, JPA가 정의한 엔티티 매니저를 구현하며, JDBC를 사용하여 데이터베이스 연결, SQL 쿼리 생성 및 실행, 객체-테이블 매핑하는 등 실제 동작을 수행하는구현체이다.

아래 코드를 보며 이해해보자.

  • EntityManager, @Entity, @Table, @Id, GeneratedValue 등은 모두 JPA 표준 인터페이스/어노테이션이다.
  • EntityManager의 find() 메소드도 JPA가 정의한 메소드이다.
  • find() 메소드를 실행하면 Hibernate가 구현한 find()메소드를 실행하여 실제 동작(User 엔티티에서 id가 1L인 사용자 조회)를 수행한다.
  • 이때 Hibernate가 구현한 find() 메소드는 DB와 JAVA와 DB 간에 통신을 JDBC를 통해 구현한다.
// JPA 인터페이스 (javax.persistence)
EntityManager em = ...; // EntityManager는 JPA 인터페이스

// 엔티티 (JPA 어노테이션 사용)
@Entity
@Table(name = "users")
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String name;
    // ...
}

// JPA를 사용한 데이터 조회
User user = em.find(User.class, 1L); // find()는 JPA EntityManager 인터페이스의 메서드

SQL Mapper

SQL Mapper란?

객체의 필드와 SQL을 매핑하여 데이터를 객체화하는 기술이다.
ORM과 다르게 객체 중심이 아닌 쿼리 중심으로써 개발자가 직접 쿼리를 작성한다.

SQL Mapper 장단점

  • 장점
    • ORM에서 발생하는 성능 문제(JPA N+1 문제 등)를 방지할 수 있다.
    • 쿼리를 직접 작성하기 때문에 복잡한 쿼리(조인, 서브 쿼리 등)을 효율적으로 사용할 수 있다.
    • JDBC를 사용했을 때 발생하는 불필요한 코드들(객체 매핑, 파라미터 바인딩, 동적 쿼리 등)을 줄일 수 있다.
  • 단점
    • 쿼리를 개발자가 직접 작성해야 한다.
    • 특정 DBMS(MySQL, Oracle 등)에 종속된다.
    • 쿼리 중심이기 때문에 ORM의 객체 지향적인 설계의 장점을 누리지 못할 수 있다.
JDBC 대비 장점
  • 객체 매핑
    JDBC는 객체를 직접 추출하여 매핑해야 한다.
// JDBC 예시 (ResultSet에서 데이터를 수동으로 추출)
ResultSet rs = preparedStatement.executeQuery();
List<User> users = new ArrayList<>();
while (rs.next()) {
    User user = new User();
    user.setId(rs.getLong("id"));
    user.setName(rs.getString("name"));
    user.setEmail(rs.getString("email"));
    users.add(user);
}

하지만 MyBatis는 XML에 객체를 명시하여 자동으로 매핑할 수 있다.

<!-- MyBatis XML 예시 (자동 매핑) -->
<select id="selectUsers" resultType="com.example.User">
    SELECT id, name, email FROM users
</select>
  • 파라미터 바인딩
    JDBC는 코드를 통해 직접 바인딩해야 한다.
// JDBC 예시 (PreparedStatement 사용)
PreparedStatement pstmt = connection.prepareStatement(
        "SELECT * FROM users WHERE id = ? AND name = ?"
);
pstmt.setLong(1, userId); // 첫 번째 ?에 userId 값 바인딩
pstmt.setString(2, userName); // 두 번째 ?에 userName 값 바인딩

MyBatis는 명시한 객체의 파라미터 이름을 통해 바인딩할 수 있다.

<!-- MyBatis XML 예시 (파라미터 바인딩) -->
<select id="selectUserByIdAndName" resultType="com.example.User">
    SELECT * FROM users WHERE id = #{id} AND name = #{name}
</select>
  • 동적 SQL(쿼리)
    Mybatis는 조건문, 반복문 등을 사용하여 쿼리를 동적으로 생성할 수 있다.
<!-- MyBatis XML 예시 (동적 SQL) -->
<select id="selectUsers" resultType="com.example.User">
    SELECT * FROM users
    <where>
        <if test="name != null">
            AND name = #{name}
        </if>
        <if test="email != null">
            AND email = #{email}
        </if>
    </where>
</select>

JPA란?

엔티티 매니저 팩토리(EntityManagerFactory)와 엔티티 매니저(EntityManager)

  • Entity
    DB 테이블과 매핑되는 객체
  • EntityManagerFactory
    EntityManager를 생성하고 관리하는 interface
    EntityManager가 생성되면 1:1로 persistent context가 생성됨
    @PersistenceContext : 엔티티 팩토리 매니저 주입
  • EntityManager
    엔티티를 관리하는 역할
    @PersistenceContext : 엔티티 매니저 주입

영속성 컨텍스트란?

어플리케이션과 DB 사이에 객체를 영구적으로 보관하는 가상 DB 역할(캐시 서버 역할)
트랜잭션 커밋 시점에 영속성 컨텍스트에 저장된 데이터를 DB에 한번에 저장(EntitiManager.flush())한다.

  • 영속성 컨텍스트(persist context)
영속성 컨텍스트 역할
  • 1차 캐시
    • 영속성 컨텍스트는 내부에 엔티티를 보관하는 1차 캐시를 가지고 있다.
    • 엔티티를 조회할 때 먼저 1차 캐시를 확인하고, 없으면 데이터베이스에서 조회하여 1차 캐시에 저장한다.
    • 이후 동일한 엔티티를 다시 조회하면 데이터베이스에 접근하지 않고 1차 캐시에서 가져온다.
  • 쓰기 지연 (Transactional Write-behind)
    • 엔티티를 변경(persist, remove 등)해도 바로 데이터베이스에 반영되지 않고, 영속성 컨텍스트 내부에 SQL 쿼리를 쌓아둔다.
    • 트랜잭션 커밋 시점에 쌓아둔 쿼리를 한 번에 데이터베이스에 보내어 (flush) 데이터베이스 접근 횟수를 줄인다.
  • 변경 감지 (Dirty Checking)
    • 영속성 컨텍스트는 엔티티의 스냅샷을 보관하고 있다가, 트랜잭션 커밋 시점에 엔티티의 변경 사항을 감지하여 변경된 내용만 UPDATE 쿼리를 생성한다.
  • 지연 로딩 (Lazy Loading) - 특정 객체만 가져옴?
    • 연관된 엔티티를 즉시 로딩하지 않고, 실제로 사용되는 시점에 로딩한다.
    • 지연 로딩 설정을 하면 프록시 객체를 생성하고 실제 사용되는 시점에 로딩하여 불필요한 데이터베이스 조회를 줄여 성능을 향상시킨다.
    // @PersistenceContext : Spring이 EntityManager를 생성해서 스프링 빈에 주입
    @PersistenceContext
    private EntityManager em;

영속성 컨텍스트 저장 & 조회

  • 영속성 컨텍스트에 엔티티 저장 : EntityManager.persist(entity)
    key:value 형태로 데이터가 저장되며 key == 객체의 id 값
private EntityManager em;

public void save(Member member) {
        em.persist(member); // 영속성 컨텍스트에 member 엔티티 저장
    }
  • 영속성 컨텍스트에서 엔티티 조회 : EntityManager.find(entity)
private EntityManager em;

public Member findOne(Long id) {
        return em.find(Member.class, id); // 영속성 컨텍스트에서 member를 찾아서 반환
    }
  • 영속성 컨텍스트에 엔티티가 있는 경우
    영속성 컨텍스트에서 엔티티 반환

  • 영속성 컨텍스트에 엔티티가 없는 경우
    DB에서 엔티티 조회해서 영속성 컨텍스트에 저장한 후 영속성 컨텍스트에서 반환

 

  • 출처

출처

https://colevelup.tistory.com/21
https://velog.io/@kimdy0915/Transactional-%EC%82%AC%EC%9A%A9%EA%B3%BC-%EC%98%81%EC%86%8D%EC%84%B1-%EC%BB%A8%ED%85%8D%EC%8A%A4%ED%8A%B8persistence-context
https://makemepositive.tistory.com/49

'Back-end' 카테고리의 다른 글

객체 지향 설계의 5가지 원칙(SOLID)  (4) 2024.09.13
'Back-end' 카테고리의 다른 글
  • 객체 지향 설계의 5가지 원칙(SOLID)
토자맨
토자맨
  • 토자맨
    개발하는 토자맨
    토자맨
  • 전체
    오늘
    어제
    • 개발 공부
      • 코딩 테스트
        • 코드업 기초 100제
        • 백준
        • 99클럽
        • 자료구조
        • 알고리즘
      • Programming Language
        • 자바(JAVA)
      • Back-end
        • Spring
      • Front-end
        • html
        • css
      • DevOps
        • AWS
        • CI CD
        • Docker
        • 홈서버
        • Git
      • Computer Science
        • 자료구조
        • 알고리즘
        • 운영체제
        • OS,Network,DB,DesignPattern
      • 프로젝트
        • 웨이트 쇼핑몰
      • 공부 로드맵
        • 2학년 겨울방학
        • 3학년 2학기
        • 3학년 겨울방학
      • 일상
        • 기타 정보
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    bfs #최단거리탐색 #프로그래머스
    bfs #백준
    dfs #백준
    티스토리챌린지
    백준 #dfs #11725번
    dp #백준 #동적계획법
    git filter-branch #commit 수정 #commit
    nvidia-docker #docker cuda #docker gpu #엔비디아 도커
    백준 #dp #동적계획법
    백준 #dfs #알고리즘
    싱글톤 패턴 #싱글톤 컨테이너 #싱글톤 레지스트리 #싱글톤 객체 상태 #무상태 #stateless #유지상태 #staleful
    99클럽 #코딩테스트 준비 #개발자 취업 #항해99 #til
    이진탐색 #이분탐색 #알고리즘
    프로그래머스 #dfs
    이진탐색 #이분탐색 #백준
    오블완
    백준 #아기상어2 #bfs
    git filter-repo
    프로그래머스 #dp
    백준 #이진탐색 #이분탐색
    백준 #bfs
    백준 #dfs
    스프링 #spring #스프링 컨테이너 #스프링 컨텍스트
    ec2 멈춤 #ec2 터짐 #ec2 ssh 연결 끊김 #ec2 끊김
    스프링핵심원리 #김영한 #의존관계자동주입 #의존관계 자동 주입
    bfs #프로그래머스
    피보나치 수 #백준 #dp
    nvidia container toolkit #
    dfs #알고리즘
    solid #객체지향설계원칙
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.0
토자맨
ORM과 SQL Mapper - Hibernate, JPA
상단으로

티스토리툴바