[Spring Data] ORM과 Spring Data JPA, 영속성 컨텍스트

Ogu·2024년 1월 7일
0

SpringData

목록 보기
1/3

기존에는 ORM이 객체 관계 매핑을 의미하며, Spring Data JPA은 SpringBoot에서 ORM을 더 편하게 활용할 수 있다는 도구다 라는 정도의 인식만 있었습니다.

현재 진행중인 프로젝트에서 Service클래스를 구현하는 데 있어 @Transactional 의 사용 이유 및 올바른 사용법에 대해 고민하던 중, 영속성 컨텍스트, 엔티티 생명주기와 같은 기본적인 개념에 대한 공부가 필요할 것 같아 관련 개념을 정리하게 되었습니다.

📕 ORM

🌱 ORM이란?

ORM은 Object Relational Mapping의 줄임말로, 객체 관계 매핑을 도와주는 도구입니다.
클래스와 RDB 테이블의 모델 간의 불일치는 어쩔 수 없이 존재합니다.
ORM은 이러한 객체 지향 언어의 객체(클래스)와, RDB의 테이블을 자동으로 매핑해 주어 매우 편리합니다. 데이터베이스의 값을 마치 객체처럼 사용할 수 있죠.


https://hanamon.kr/orm%EC%9D%B4%EB%9E%80-nodejs-lib-sequelize-%EC%86%8C%EA%B0%9C/

🌱ORM의 사용 이유와 장점

그렇다면 ORM을 사용하면 어떠한 점이 편리해질까요?

1. ORM을 사용하며 DB 쿼리를 객체지향적으로 조작할 수 있다.

SQL문을 직접 작성하지 않고도 엔티티를 객체로 표현할 수 있으며, 간접적으로 DB를 다를 수 있습니다.

2. 재사용 및 유지보수가 편리하다.
ORM을 통해 매핑된 객체는 모두 독립적으로 작성되어 있어 재사용이 용이해집니다.

3. 데이터베이스에 대한 종속성에 줄어든다.
ORM을 통해 자동 생성된 SQL문은 객체를 기반으로 DB 테이블을 관리하기 때문에 DB에 종속적이지 않습니다.

4. 직관적인 코드로 가독성이 높아진다
ORM을 이용하면 SQL이 아닌 메서드로 데이터를 조작할 수 있습니다. 따라서 더욱 객체 지향적으로 쿼리를 조작할 수 있어 코드의 가독성을 높여줍니다.
따라서 비즈니스 로직에 더욱 집중할 수 있고 생산성이 높아집니다.

🌱 ORM의 단점

굉장히 편리한 도구이지만, 단점이 없지는 않습니다.
실제 복잡한 서비스를 구현하다 보면 ORM만으로 온전히 구현하기에는 한계가 있습니다.

  1. 복잡한 서비스의 경우 직접 쿼리로 구현하지 않고 코드로만 구현하기에는 한계가 있다.
  2. 복잡한 쿼리를 상세 설계 없이 ORM만으로 구성하게 되면 속도 저하 등의 성능 문제가 발생할 수 있다.
  3. 어플리케이션의 객체 관점과 데이터베이스의 관계 관점의 불일치가 발생한다.

와 같은 단점이 있습니다.

📕 JPA와 하이버네이트, Spring Data JPA

🌱 JPA란?

JPA(Java Persistence API)는 자바 진영의 ORM 기술 표준으로 채택된 인터페이스의 모음입니다.
JPA는 ORM의 큰 개념에서 좀 더 구체화된 스펙을 제공합니다. JPA도 ORM과 같이 실제로 동작하는 것이 아니고 동작 메커니즘을 정리한 표준 명세(인터페이스)입니다.

JPA는 내부적으로 JDBC API를 사용하고 있습니다. 따라서 적절한 SQL을 대신 생성하고 데이터베이스를 조작해 객체를 자동 매핑해줍니다.

🌱하이버네이트

대표적인 JPA 기반의 구현체로 Hibernate, EclipseLink, DataNucleus 등이 있습니다. 그중 가장 많이 사용되는 구현체는 하이버네이트입니다.
즉, 하이버네이트는 JPA가 정의하는 인터페이스를 구현하고 있는 JPA 구현체 중 하나이죠.

🌱Spring Data JPA

Spring Data JPA는 하이버네이트의 기능을 더욱 편하게 사용하도록 모듈화한 것입니다.
CRUD 처리에 필요한 인터페이스를 제공하고 하이버네이트의 엔티티 매니저(Entity Manager)를 직접 다루지 않고 리포지토리(Repository)를 정의해 사용하며 스프링이 적합한 쿼리를 동적으로 생성하는 방식으로 DB를 조작합니다.

페이징 처리 및 메서드 이름으로 자동으로 쿼리 빌딩하는 기능 등을 제공합니다.

🌱 영속성 컨텍스트

영속성 컨텍스트(Persistence Context)는 애플리케이션과 DB 사이에서 엔티티와 레코드의 괴리를 해소 및 객체를 보관합니다. 즉, 엔티티를 관리하는 가상의 공간인 셈입니다.

엔티티가 영속성 컨텍스트에 들어오면 JPA는 엔티티 객체의 매핑 정보를 DB에 반영합니다.
또한 엔티티 객체가 영속성 컨텍스트에 들어와 JPA의 관리 대상이 되면 해당 객체를 영속 객체라고 부릅니다.


https://developer111.tistory.com/84

엔티티 매니저

엔티티 매니저(Entity Manager) 는 이러한 과정에서 영속성 컨텍스트를 관리하는 객체입니다.
말그대로 엔티티를 관리하며, CRUD작업을 수행합니다.
엔티티 매니저는 엔티티 매니저 팩토리(EntityManagerFactory)가 만듭니다.

하나의 요청에 관해 데이트 베이스에 접근하기 위한 세션이 생성되면 영속성 컨텍스트를 생성해주고, 세션이 종료되면 영속성 컨텍스트도 사라집니다.

그렇다면 스프링 부트에서는 어떻게 관리하고 있을까요?
스프링 부트는 내부에서 엔티티 매니저 팩토리를 하나만 생성해서 관리하고, @PersistenceContext 또는 @Autowired 애너테이션을 사용해 엔티티 매니저를 사용합니다.

@PersistenceContet
EntityManager em;  // 프록시 엔티티 매니저

하지만 스프링 부트는 기본적으로 빈은 하나만 생성해서 공유하므로 동시성 문제가 발생할 수 있습니다. 그래서 실제로는 엔티티 매니저가 아닌 실제 엔티티 매니저와 연결하는 프록시(가짜) 엔티티 매니저를 사용합니다. 필요할 때 진짜 엔티티 매니저를 호출하죠.

따라서 SpringBootJPA에서 엔티티 매니저를 자동 관리하므로 우리가 직접 관리할 필요가 없습니다.

영속성 컨텍스트의 특징

💡 1차 캐시
영속성 컨텍스트는 내부에 1차 캐시를 가집니다.
영속성 상태의 엔티티는 HashMap(key(@Id) = value(Entity)) 의 형태로 저장됩니다.
엔티티를 조회하면 1차 캐시에서 데이터를 조회하고 값이 있으면 반환합니다. 값이 없으면 DB에서 조회해 1차캐시에 저장하여 반환합니다.

따라서 캐시된 데이터를 조회할 때는 DB를 거치지 않으므로 DB 접속을 최소화하여 빠르고 효율적으로 데이터를 조회할 수 있습니다.

💡 쓰기 지연
쓰기 지연은 트랜잭션을 커밋하기 전까지는 DB에 실제로 질의문을 보내지 않고, 쿼리를 모았다가 트랜잭션을 커밋하면 모았던 쿼리를 한번에 실행합니다.

예를 들어, 데이터 추가 쿼리가 3개라면, 영속성 컨텍스트는 트랜잭션을 커밋하는 시점에 3개의 쿼리를 한꺼번에 전송합니다.

💡 변경 감지
JPA는 update 관련 API를 따로 제공하지 않습니다.
save() 를 실행하면 JPA에서는 더티 체크(Dirty Check)라고 하는 변경 감지를 수행해 반영하는데요,
트랜잭션을 커밋하면 1차 캐시에 저장되어 있는 엔티티의 값과 현재 엔티티의 값을 비교하고, 변경사항을 감지해 DB에 자동으로 반영합니다.

따라서 쓰기 지연과 마찬가지로 적당한 묶음으로 쿼리를 요청해 DB시스템의 부담을 줄일 수 있습니다.

💡 지연 로딩
쿼리로 요청한 데이터를 바로 로딩하는 것이 아니고, 필요할 때(실제 작업 실행 시) select 쿼리를 날려 조회합니다.

엔티티의 생명 주기(상태)

엔티티 객체는 영속성 컨텍스트에서 4가지 상태로 구분할 수 있습니다.
번역된 한국어보단 원어인 영어 단어가 조금 더 쉽게 와닿는 것 같습니다.

https://velog.io/@hye_b/JPA-3

  • 💡 비영속(New)
    영속성 컨텍스트에 추가되지 않은 엔티티 객체 상태

  • 💡 영속(Managed)
    영속성 컨텍스트에 저장된 상태

  • 💡 준영속(Detached)
    영속성 컨텍스트에 저장되었다가 컨텍스트와 분리된 상태

  • 💡 삭제(Removed)
    데이터베이스에서 레코드를 삭제하기 위해 영속성 컨텍스트에 삭제 요청을 한 상태

JPA를 조금 더 올바르게 사용하기 위해 ORM부터 SpringDataJPA, 영속성 컨텍스트와 그 관련된 개념들에 대해 알아보았습니다.
위 개념들을 이해하고 다음 실제 코드 작성 관련 포스팅에 적용해보겠습니다.

참고

다음 공부

  • @Transactional의 올바른 사용법
profile
私はゲームと日本が好きなBackend Developer志望生のOguです🐤🐤

0개의 댓글