엔티티(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; }
- GenerationType.AUTO
기본키 생성 전략 참고 자료
엔티티 매니저(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
쓰기 지연 저장소(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
'Language > Spring' 카테고리의 다른 글
[공통처리] Filter, Interceptor, AOP 차이점 및 흐름과 역할 (0) | 2024.11.15 |
---|---|
[AOP] AOP란? (1) | 2024.11.14 |
[JPA/Hibernate] Hibernate 기초 (1) | 2024.11.09 |
[JPA] JPA의 개념 / JPA를 사용해야하는 상황과 그렇지 못한 상황 (1) | 2024.11.08 |
[Redis] 캐시란? (0) | 2024.09.07 |