반응형
EntityManager
- EntityManager는 Entity(객체와 테이블이 매칭되는 개념)를 관리하는 역할을 합니다.
- EntityManagerFactory가 요청이 올때마다 생성하는 비용이 매우 크기 때문에, 대신 생성비용이 거의 없는 EntityManager가 생성됩니다.
public interface EntityManagerFactory {
/**
* Create a new application-managed <code>EntityManager</code>.
* This method returns a new <code>EntityManager</code> instance each time
* it is invoked.
* The <code>isOpen</code> method will return true on the returned instance.
* @return entity manager instance
* @throws IllegalStateException if the entity manager factory
* has been closed
*/
public EntityManager createEntityManager();
// ...
}
- 단, EntityManager는 Thread-safe하지 않기 때문에 여러 스레드가 동시에 접근하면 동시성 문제가 발생합니다.
그래서 요청 별로 한 개씩 할당합니다. - EntityManager는 내부적으로 Database Connection을 사용하여 데이터베이스에 접근합니다.
영속성 컨텍스트
- Entity를 영구 저장하는 환경으로, 애플리케이션과 데이터베이스 사이에서 객체를 보관하는 논리적 개념입니다.
- EntityManager를 통해 Entity를 보관하고 관리합니다. (EntityManager가 생성되면 연속성 컨텍스트가 1:1로 생성됩니다.)
- 영속성 컨텍스트 내에서 Entity를 식별자 값을 이용해서 구분하는데, 식별자 값은 테이블의 기본 키와 매핑한 값 (@Id)입니다.
영속성 컨텍스트의 특징이자 이점
1차 캐시
- 1차 캐시는 key와 value로 이루어진 저장소로, key값에는 엔티티의 id값이, value에는 해당 Entity가 들어갑니다.
- 1차 캐시에 엔티티를 저장해놓으면 조회할 때 좋습니다.
예로, 1차 캐시에 id가 "review1"인 member 엔티티가 있을 때, 서비스에서 member1이라는 id를 가진 엔티티를 조회한다면 DB로 쿼리가 날라가지 않고 1차 캐시의 ID 값을 참조해서 조회한다.
만약 1차 캐시에 없는 엔티티(id가 "review2")가 1차 캐시에 없다면?
EntityManager가 flush()를 통해 데이터베이스에 접근하여 "review2"라는 ID를 가진 엔티티를 조회한 후, 사용자에게 제공하면서 동시에 1차 캐시에도 저장합니다.
- 1차 캐시는 영속성 컨텍스트가 삭제될 때 같이 삭제되므로, 애플리케이션 전체에서 공유하는 공간이 아닙니다. (2차 캐시는 애플리케이션 전체에서 공유합니다.)
동일성 보장
같은 Entity를 두번 조회할 때 두 Entity는 동일한 Entity를 보장하는, 동일성이 보장됩니다.
트랜잭션을 지원하는 쓰기 지연
- 트랜잭션 내부에서 persist()가 일어날 때,
- 엔티티들을 1차 캐시에 저장하면서 동시에, INSERT 쿼리들을 생성해서 쓰기 지연 SQL 저장소에 저장합니다.
- commit() 또는 flush() 할때 쓰기 지연 SQL 저장소에 저장되어 있는 SQL들을 DB에 보냅니다.
변경 감지 (Dirty Checking)
- Entity를 업데이트할 때 따로 update()와 같이 직접 쿼리문을 날리지 않아도 됩니다. (아래와 같이 객체만 수정해도 O)
- EntityManager는 Entity를 1차 캐시에 저장할 때 스탭샷(최신 상태)도 함께 저장합니다.
- 트랜잭션이 커밋하는 시점에서 Entity와 스냅샷을 비교하여 변경사항이 있을 경우,
자동으로 Update SQL을 생성하여 쓰기 지연 저장소에 저장합니다.
Member findMember = em.find(Member.class, "memberA");
findMember.setName("B");
플러시 (Flush)
- 영속성 컨텍스트의 변경 내용을 데이터베이스에 반영(동기화)하는 작업입니다.
- 트랜잭션 commit 시점에 플러시가 발생하는데, 이때 쓰기 지연 SQL 저장소에 있는 SQL문들을 모두 데이터베이스로 전송합니다.
방법은 3가지입니다.
- em.flush() (수동 호출)
- 트랜잭션 commit (자동 호출)
- JPQL 쿼리 실행 (자동 호출)
반응형
'백엔드 개발하며 작성한 > 데이터베이스' 카테고리의 다른 글
[ORM] 상속 관계 매핑 (0) | 2022.05.20 |
---|---|
[ORM] 연관관계의 주인을 정해야하는 이유 (0) | 2022.05.20 |
[MySQL]날짜/시간 타입과 TIMESTAMP 칼럼 생성 (0) | 2021.10.08 |
[MySQL Workbench] ERD를 SQL 코드로 변환하기 (0) | 2021.09.02 |
cmd로 MongoDB에 데이터 저장하기 (0) | 2021.05.20 |