JPA에서 persistence context 이점에 대한 단상

hyungjunn·2025년 12월 27일

영속성 컨텍스트(persistence context)는 EntityManager가 관리하는, 특정 시점에 영속 상태로 존재하는 엔티티 인스턴스들의 모음이다. 여기서 "영속" 상태라는 것에 주목할 필요가 있다. 보통 컴퓨터 과학에서 영속(persistence)은 디스크 db처럼 영구적인 저장소에 저장된 상태를 의미한다. 하지만 영속성 컨텍스트 자체는 메모리에 존재한다. 그렇다면 왜 "영속"이라는 이름을 붙혔을까? 이는 DB와 동기화가 보장되는 상태를 의미하기 때문이다. 즉, 영속 상태의 엔티티는 db에 존재하거나, 트랜잭션 커밋 시점에 db에 반영될 것이 약속된 상태다.

그렇다면 왜 이러한 중간 계층을 두는 걸까? 영속성 컨텍스트는 엔티티를 메모리에서 관리함으로써 캐싱 효과, 동일성 보장, 변경 감지(dirty checking), 쓰기 지연(write-behind)같은 이점을 보장한다. (여기서 캐싱 효과는 엄밀히 말해서 1차 캐시와는 다른 것이다.)

First-level cache

JPA의 persistence context에서는 동일한 PK에 대하여 동일한 엔티티 인스턴스를 반환하도록 정의되어 있다. Hibernate에서는 이를 first-level cache라고도 부른다. 이를 통해 객체 동일성과 값의 일관성을 모두 확보할 수 있다.

first-level cache는 application-level repeatable reads를 제공해준다^1. 캐싱 효과도 있지만, 그것이 주된 목적이 아니다. DB가 READ COMMITTED isolation level일 때, Non-Repeatable Read 문제가 발생할 수 있다. first-level cache는 이를 애플리케이션 레벨에서 보완한다.

-- 트랜잭션 A
SELECT * FROM MEMBER WHERE id = 1; -- '철수'

-- 트랜잭션 B
UPDATE MEMBER SET USERNAME = '영희' WHERE id = 1;
COMMIT;

-- 트랜잭션 A
SELECT * FROM MEMBER WHERE id = 1; -- '영희'
Member a = em.find(Member.class, 1L); // first-level cache에 저장, name = '철수'

// 트랜잭션 B가 DB 변경 후 COMMIT

Member b = em.find(Member.class, 1L); // first-level cache에서 바로 반환, name = '철수'

위와 같이 DB에서는 READ COMMITTED인데 applicatoin단에서는 repeatable read처럼 동작하게 한다.

0개의 댓글