혹시 JPA 개발 하면서 "왜 쿼리가 중복 실행되지?" "업데이트 한 건 왜 반영 안 되지?" 이런 경험 있으신가요? 🤔 관련하여 오늘은 JPA 영속성 컨텍스트에 대해 알아볼꺼에요
🐰 JPA 영속성 컨텍스트란 무엇일까?
가장 먼저, 영속성 컨텍스트는 JPA가 관리하는 1차 캐시라고 보면 돼요. 데이터베이스에서 읽거나 저장하려는 엔티티 객체들을 일시적으로 보관하는 저장소라고 생각하면 쉬워요
JPA에서는 EntityManager라는 친구가 이 영속성 컨텍스트를 관리합니다. 정말 중요한 점은, 같은 트랜잭션 안에서는 같은 엔티티를 여러 번 조회해도 DB hits는 단 1번이라는 사실!
💡 트랜잭션 내에서 동일한 엔티티 조회 시 DB 쿼리는 1회만 발생해 성능 최적화 효과 만점!
그래서 실제 코드에서 이렇게 적용할 수 있어요
@Entity
public class User {
@Id
private Long id;
private String name;
// getters and setters omitted for brevity
}
// 서비스 메서드 예제
@Transactional
public void example(EntityManager em) {
User user1 = em.find(User.class, 1L);
User user2 = em.find(User.class, 1L);
System.out.println(user1 == user2); // true 출력 - 같은 인스턴스
}
- 위 코드는 같은 트랜잭션 내 두 번 조회했는데도 DB는 한 번만 접근하고, 반환된 객체는 완전 동일해요
🐰 왜 JPA 영속성 컨텍스트가 중요할까?
영속성 컨텍스트가 없으면 매번 쿼리를 날려야 해서 성능이 뚝 떨어져요. 그리고
엔티티의 상태 변화 추적과 쓰기 지연 기능 덕분에, 수정 사항을 눈에 보이지 않는 곳에서 자동으로 처리하니까 업무 로직이 훨씬 깔끔해져요.
예를 들어 아래처럼 수정해도 커밋 시점에 한꺼번에 UPDATE 쿼리가 나갑니다
@Transactional
public void updateUser(EntityManager em) {
User user = em.find(User.class, 2L);
user.setName("새 이름");
// 별도 em.persist 필요 없음 - 변경사항 감지 자동 처리됨
}
- 이렇게 하면 개발자가 직접 UPDATE 쿼리를 작성하지 않아도 돼요
⚠️ 단, 트랜잭션 밖이나 detach 상태에서는 변경 감지가 안 되니 주의!
🐰 JPA 영속성 컨텍스트는 어떻게 관리되고 있을까?
매 요청마다 EntityManager (또는 Spring 기준으로 @PersistenceContext로 주입된 EntityManager)는 내부적으로 새로운 영속성 컨텍스트를 생성합니다.
즉, 한 요청(트랜잭션)당 하나의 영속성 컨텍스트가 있고 종료와 함께 사라진다고 보면 됩니다.
실제로 좋은 점은 이 범위 내에서 객체 동일성을 보장한다는 거예요. 그래서 아래처럼 동작해요
- find()로 조회 후 해당 엔티티 객체 수정하면,
- commit 시점에 변경내용을 DB에 반영.
- 다시 find() 실행 시 기존 인스턴스를 바로 반환.
💡 즉, 엔티티를 새로 매핑하지 않고 캐시된 객체를 재사용해서 메모리와 시간을 절약해요
🐰 왜 엔티티 업데이트 반영이 안되지?
예전에 detach 상태인 엔티티를 수정하려고 했다가 업데이트가 안 되어 이유를 몰랐던 적이 있었는데요 🥲 아래 세 가지를 이해하고 있으면 좋아요
- merge() : detach된 엔티티를 다시 영속 상태로 복구하려면 merge() 필수
- 트랜잭션 범위 확인: 트랜잭션 밖 작업은 변경 감지가 안 돼서 의도치 않은 결과 발생
- clear(), detach() 호출 주의: 의도치 않게 캐시를 비웠다면 재조회해야 정상 동작
아래 코드는 merge 사용 예시입니다
@Transactional
public void updateDetachedUser(EntityManager em, User detachedUser) {
User managedUser = em.merge(detachedUser); // 다시 영속 상태로 복구!
managedUser.setName("venny");
}
- 분리된 객체라도 merge로 붙이면 업데이트 가능해요
⚠️ merge 후 반환받은 인스턴스를 꼭 사용해야 해요! 이전 객체는 여전히 detach에요
🐰 결론
JPA (Java Persistence API)의 영속성 컨텍스트는 “DB와 객체 사이의 진실을 맞춰주는 핵심 레이어”라서 여기서 삐끗하면 성능, 데이터 정합성, 트랜잭션 안정성까지 한 번에 무너집니다😵
🐰 3가지 요약
- JPA 영속성 컨텍스트는 트랜잭션 내 1차 캐시 역할로 쿼리 횟수를 줄여준다
- 변경 감지 및 쓰기 지연 덕분에 개발자는 명령형 SQL 관리 부담에서 벗어난다
- detach 상태나 트랜잭션 경계 관리를 잘못하면 데이터 꼬임과 성능 저하 위험이 증가한다
다음글은 영속성 컨텍스트를 잘 쓰는법에 대해 자세하게 작성해보겠습니닿
