본문 바로가기

Language/Spring

[Entity] 엔티티와 영속성 컨텍스트

엔티티(Entity)란?
  • 비즈니스 요구 사항을 모델링한 객체
엔티티 설정의 필수 사항
  • 기본 생성자 필수
  • @Entity 어노테이션
    • name의 속성(테이블명) 지정 가능
    • 기본값은 클래스 이름과 동일
  • @Id
    • 영속성 컨텍스트에서 엔티티를 관리할 때 구분하기 위해 사용(식별자 역할)
  • @GeneratedValue
    • JPA 기본키 생성 전략
    • 4가지 설정 존재
      • GenerationType.AUTO
        •  hibernate.dialect에 설정된 DB 종류에 따라 하이버네이트가 자동으로 전략 선택
        • 단, 하이버네이트를 무조건 신뢰해서는 안 됨
          • MySQL의 경우 AUTO 설정을 하면 당연히 Identity 전략을 취할 것이라 생각하고 생략하거나, 추후 DMBS 종류 변경을 고려하여 AUTO로 사용하는 경우가 있는데, 버전에 따라 선택되는 전략이 달라질 수 있기 때문에 직접 DBMS에 맞는 전략을 지정
      • GenerationType.Identity
        • 기본 키 생성을 데이터베이스에 위임
        • 주로 MySQL, PostgreSQL, SQL Server, DB2에서 사용 (MySQL의 AUTO_ INCREMENT)
        • JPA는 보통 트랜잭션이 commit 되는 시점쓰기 지연 저장소에 모아놓은 SQL을 한 번에 DB로 전송하며 실행하기 때문에 애플리케이션과 DB 사이에 네트워크를 오가는 횟수가 줄어들어 성능면에서 이득을 볼 수 있음
        • 하지만, IDENTITY전략은 DB에 기본키 생성을 위임하므로 JPA 입장에선 DB에 INSERT SQL를 실행하기 전엔 기본 키( AUTO_INCREMENT되는 값)를 알 수 없으므로 persist() 시점에 insert 쿼리가 실행
          영속성 컨텍스트로 엔티티를 관리하려면 1차 캐시에 Id값을 key 값으로 들고 있어야 하기 때문
        • 즉, Identity 전략은 DB의 접근을 줄이는 JPA의 기능을 상실하여 성능이 중요한 상황에서 적합하지 않음
      • GenerationType.SEQUENCE
        • DB의 시퀀스를 활용하여 Id값을 증가시킴
        • 오라클, PostgreSQL, DB2, H2 데이터베이스에서 사용
        • 데이터베이스 시퀀스는 유일한 값을 순서대로 생성하는 특별한 데이터베이스 오브젝트
          Ex) 오라클 시퀀스
        • sequenceName으로 시퀀스를 분리하여 지정할 수 있고 allocationSize로 한 번에 사용할 시퀀스 덩어리 사이즈를 지정해서 최적화 가능
        • @Entity 
          @SequenceGenerator( 
               name = “MEMBER_SEQ_GENERATOR", 
               sequenceName = “MEMBER_SEQ", //매핑할 데이터베이스 시퀀스 이름
               initialValue = 1, allocationSize = 50) 
          public class Member { 
               @Id @GeneratedValue(strategy = GenerationType.SEQUENCE, 
               generator = "MEMBER_SEQ_GENERATOR") 
               private Long id; 
           
           }
      • GenerationType.TABLE
        • 키 생성 전용 테이블을 하나 만들어서 데이터베이스 시퀀스를 흉내내는 전략
        • 모든 데이터베이스에 적용 가능하나, 성능적인 손해가 있어서 잘 쓰지 않음
        • @Entity 
          @TableGenerator(
               name = "MEMBER_SEQ_GENERATOR", 
               table = "MY_SEQUENCES", 
               pkColumnValue = “MEMBER_SEQ", allocationSize = 1) 
          public class Member { 
               @Id 
               @GeneratedValue(strategy = GenerationType.TABLE, 
               generator = "MEMBER_SEQ_GENERATOR") 
               private Long id; 
           }
           
기본키 생성 전략 참고 자료

https://devcamus.tistory.com/16#--%--GenerationType-AUTO%--%EC%--%B-%EC%--%----%EC%-E%--%EB%-F%--%EC%-C%BC%EB%A-%-C%--IDENTITY%-C%--SEQUENCE%-C%--TABLE%--%E-%B-%AD%--%ED%--%-D%----


 

엔티티 매니저(EntityManager)란?
  • 엔티티를 CRUD 하는 등 엔티티와 관련된 모든 일을 처리
  • 엔티티를 관리하는 가상의 데이터베이스로 생각할 수 있음
  • 엔티티 매니저는 영속성 컨텍스트와 1대1 또는 1대N 관계를 가짐
  • EntityManager를 만들기 위해서는 EntityManagerFactory를 통해 생성
JPA 2.1 명세 문서  '7.1 Persistence Context'
- 엔티티 매니저의 종류를 컨테이너 관리형과 애플리케이션 관리형으로 나뉨

> 컨테이너 관리형
- Java EE 환경의 경우, 보통 한 트랜잭션 내에서 여러 컴포넌트를 호출하는 경우가 많음
- 이 때 한 트랜잭션 내에서 같은 영속성 컨텍스트가 공유돼야 하는 경우가 발생
- 이를 Java EE 컨테이너가 각 컴포넌트에 엔티티 매니저를 주입해줄 때 같은 영속성 컨텍스트가 전파되도록 함

> 애플리케이션 관리형
- Java EE 환경에서 흔하지 않지만, 같은 트랜잭션 내에서 각 엔티티 매니저들이 독립적인 영속성 컨텍스트를 가져야하는 경우 존재
- 이 때 애플리케이션에서 직접 엔티티 매니저 팩토리를 통해 엔티티 매니저를 만들고 직접 닫음
- Java SE와 Java EE Application client container 환경에서는 무조건 이 방식만 사용 가능

> 요약
- Java EE 환경에서는 한 영속성 컨텍스트가 여러 엔티티 매니저에 포함되는 1:N 관계가 될 수 있음
- Java SE 및 Java EE ACC에서는 1:1 관계만 허용

엔티티매니저팩토리(EntityManagerFactory)란?
  • JPA에서 영속성 유닛을 관리하는 핵심 객체로, 애플리케이션에서 하나의 DB에 대해 하나의 EntityManagerFactory만 생성
  • 이 객체는 애플리케이션이 종료될 때까지 존재하며, DB 연결을 설정하고 EntityManager 객체를 생성하는 역할
  • EntityManagerFactory를 생성하려면 DB 연결 정보와 JPA 설정을 포함하는 persistence.xml 파일 필요
  • 이 파일은 META-INF 폴더에 위치해야 하며 DB 연결 정보, 엔티티 클래스, 트랜잭션 처리 방식 등을 설정 가능

영속성 컨텍스트(Persistence Context)란?
  • JPA 명세에 따르면 영속성 컨텍스트는 영속성 엔티티 인스턴스들의 모음
  • 엔티티의 생명주기를 관리
  • 즉, 영속성 컨텍스트는 엔티티의 CRUD를 담당하면서 저장했거나 불러온 엔티티를 기억하는 1차 캐시 역할

 

  • 컨텍스트는 문맥이라는 뜻으로 현실에서 사람들이랑 대화를 할 때 한번 나온 얘기를 기억하고 다시 묻지 않음
  • 이처럼 영속성 컨텍스트는 엔티티를 기억하는 것이라고 이해
    → 영속성 컨텍스트는 1차 캐시로써 역할
  • 엔티티를 기억하므로 영속성 컨텍스트는 다음과 같은 장점을 가짐
    • 캐싱 : 애플리케이션에서 동일한 엔티티를 여러번 조회 시 DB에 접근하지 않고 엔티티 반환
    • 더티 체킹 : 캐싱된 엔티티를 활용해 애플리케이션에서 엔티티 변경 시 기존과 바뀐 내용이 있는지 파악 가능
    • 동일성 보장 : 캐싱 덕분에 같은 엔티티를 여러 번 조회해도 동일성을 보장

영속성 컨텍스트 = 논리적 개념
  • JPA/Hibernate에서 객체의 상태를 관리하는 영역을 나타내는 논리적인 개념
  • 구체적으로 영속성 컨텍스트는 데이터베이스와 자바 객체 간의 매핑 상태를 유지하고 관리하는 메모리 상의 영역을 의미하지만 물리적인 저장소는 아니라는 점에서 논리적 개념
    • 예를 들어, EntityManager나 Session 객체영속성 컨텍스트 역할을 함
    • 객체가 영속성 컨텍스트에 들어가면 해당 객체는 DB와 매핑되어 데이터를 갱신하고, 변경된 사항은 DB에 저장될 때까지 메모리 상에서 관리
    • 이 과정은 물리적인 DB 접근 없이도 객체 간 상태 변경을 추적할 수 있기 때문 성능과 관리 측면에서 매우 효율적
  • 따라서, 영속성 컨텍스트는 물리적인 DB와 분리된, 객체와 DB 간의 상태 관리 및 동기화 책임을 지는 논리적인 개념

엔티티의 생명 주기
  • 엔티티는 영속성 컨텍스트에 의해 생명주기가 관리
  • 생명주기는 4가지 상태가 존재
    • 비영속 (new/transient) : 영속성 컨텍스트가 모르는 상태
    • 영속 (persist) : 영속성 컨텍스트에 저장되고, 기억되고 있는 상태
    • 준영속 (detached) : 영속 상태였다가 영속성 컨텍스트가 더 이상 기억하지 않는 상태
    • 삭제 (removed) : 영속성 컨텍스트에 엔티티가 삭제될거라고 기록한 상태. 즉, 삭제되는걸 기다리는 상태
  • 즉, 영속성 컨텍스트가 기억하고 있는지 없는지로 구분 가능
    • 기억 있음 : 영속, 삭제
    • 기억 없음 : 비영속, 준영속

  • 생명 주기 4가지 상태에 대한 자세한 사항은 이전 글 참고

https://bestdevelop-lab.tistory.com/234

 

[JPA/Hibernate] Hibernate 기초

Hibernate란?객체 지향 프로그래밍과 관계형 데이터베이스 설계의 관점 차이를 해결하여 개발자가 더 객체 지향 프로그래밍에 집중할 수 있도록 해주는 ORM 중 하나Java에서는 JPA가 표준 인터페이스

bestdevelop-lab.tistory.com


쓰기 지연 저장소(Write-Behind Buffer)

  • 데이터를 변경하는 Query(Insert, Update, Delete)는 즉시 DB에 반영되는 것이 아님
  • 데이터 변경 SQL Query를 Action Queue라는 곳에 모아두었다가 flush() 혹은 commit() 명령어가 실행되는 시점비로소 DB에 반영
  • 쓰기 지연 저장소로 인하여 불필요한 Database의 접근(DB I/O)를 줄이고, 여러 개의 데이터베이스 쿼리를 하나의 배치로 묶어 처리함으로써 성능을 최적화할 수 있고, 이것이 영속성 컨텍스트를 1차 캐시로 활용하는 강점

flush()
  • 영속성 컨텍스트의 변경 내용데이터베이스에 반영하는 명령어
    = 영속성 컨텍스트 ↔ 데이터베이스 간의 동기화
  • 즉, 데이터베이스에 변경 내용을 적용하기 위해서EntityManager.flush() 혹은 EntityTransaction.commit() 명령어를 사용
    • commit() 메서드는 내부적으로 flush() 메서드를 호출하기 때문에 실질적으로는 flush() 메서드가 DB에 반영하는 명령어라고 볼 수 있음
  • flush() : 즉시 데이터베이스에 변경 내용 반영
  • commit() : 트랜잭션을 최종적으로 확정

영속성 컨텍스트 참고 자료

 

 

https://psvm.kr/posts/tutorials/jpa/3-em-and-persistence-context