스프링

JPA의 영속성 컨텍스트와 변경 감지(Dirty Checking)

zumsim 2025. 6. 21. 21:57
728x90
반응형

영속성 컨텍스트와 변경 감지 완전 정복

JPA로 개발을 하다 보면 아래와 같은 코드를 자주 보게 됩니다.

 

@Transactional
public void updateUsername(Long id, String newName) {
    User user = userRepository.findById(id).orElseThrow();
    user.setUsername(newName); // 이게 저장된다고?
}
 
cs

 

 

별도로 save()를 호출하지 않았는데, 값이 데이터베이스에 반영됩니다.
이러한 동작은 JPA의 변경 감지(Dirty Checking) 기능 덕분입니다.
이번 글에서는 이 원리가 어떻게 작동하는지 설명드리고, 실무에서 자주 발생하는 실수들과 실전 팁도 함께 정리하겠습니다.


✅ 영속성 컨텍스트란 무엇인가요?

JPA에서 엔티티 객체를 관리하는 공간을 영속성 컨텍스트(Persistence Context) 라고 합니다.
이는 EntityManager가 엔티티의 상태를 추적하고 관리하는 일종의 저장소라고 볼 수 있습니다.

JPA에서 엔티티는 총 4가지 상태를 가집니다:

상태설명
비영속 단순히 new로 생성한 객체 (DB와 무관)
영속 영속성 컨텍스트에 저장된 상태 (변경 감지 O)
준영속 컨텍스트에서 분리된 상태 (detach() 등으로)
삭제 삭제로 지정된 상태 (remove())
 

⚙️ 변경 감지(Dirty Checking)는 어떻게 작동할까요?

트랜잭션 내부에서 영속 상태인 엔티티가 수정되면,
트랜잭션이 커밋되는 시점에 JPA는 변경된 필드만 감지하여 UPDATE 쿼리를 자동으로 생성합니다.

🔸 예제

java
복사편집
@Transactional public void changeNickname(Long id, String nickname) { Member member = memberRepository.findById(id).orElseThrow(); member.setNickname(nickname); // 변경 감지 발생 }

위 코드에서는 별도의 save() 호출이 없어도
트랜잭션 종료 시점에 flush()가 호출되고, 변경 내용이 데이터베이스에 반영됩니다.


❗ 실무에서 자주 발생하는 실수들

1. 트랜잭션 없이 변경했는데 반영된 줄 착각하는 경우

java
복사편집
public void updateUser() { User user = userRepository.findById(1L).orElseThrow(); user.setUsername("newName"); // 트랜잭션이 없으면 변경 감지가 일어나지 않습니다 }

✔️ 해결 방법: 수정 로직에는 반드시 @Transactional이 선언되어 있어야 합니다.


2. DTO 매핑 후 merge() 사용

java
복사편집
User user = new User(); user.setId(1L); // 기존 사용자 user.setUsername("mergedName"); entityManager.merge(user);

merge()는 새로운 객체의 상태를 기준으로 기존 객체를 덮어쓰는 방식입니다.
필드가 누락되면 해당 값이 null로 업데이트되는 위험이 있습니다.

✔️ 해결 방법: 가능하다면 기존 엔티티를 조회한 후 필요한 필드만 명시적으로 수정하는 것이 안전합니다.


🧠 실전에서 기억해두면 좋은 팁

  • @Transactional은 변경 감지의 핵심입니다.
  • DTO → Entity 매핑 시에는 merge() 대신 조회 + setter 방식이 안전합니다.
  • flush()는 데이터베이스 반영을 강제로 수행하지만, 트랜잭션 커밋이 아니면 실제 저장은 되지 않습니다.
  • detach(), clear() 등을 호출하면 영속 상태가 해제되어 변경 감지가 작동하지 않습니다.

🔚 마무리하며

JPA는 객체 지향적인 데이터 관리를 가능하게 해주는 매우 편리한 도구입니다.
하지만 그 내부 동작 원리를 정확히 이해하지 못하면, 예상치 못한 결과나 버그가 발생할 수 있습니다.

오늘 살펴본 영속성 컨텍스트변경 감지 개념은 JPA를 안정적으로 활용하기 위한 기본 중의 기본입니다.
이 원리를 숙지해두면 엔티티 상태 변화에 대한 이해도 높아지고, 실무에서도 더 안정적인 코드를 작성할 수 있습니다.


💬 실무에서 경험했던 JPA 관련 시행착오가 있다면 댓글로 공유해 주세요.
다음 글에서는 detach(), clear(), flush() 같은 고급 메서드와
JPA 테스트 시 주의해야 할 점에 대해서도 다룰 예정입니다. 😊

728x90
반응형

'스프링' 카테고리의 다른 글

[JPA] 영속성 관리[5]  (0) 2024.12.10
[JPA] 영속성 관리[4]  (1) 2024.12.09
[JPA] 영속성 관리[3]  (1) 2024.11.27
[JPA] 영속성 관리[2]  (0) 2024.11.26
[JPA] 영속성 관리[1]  (0) 2024.11.25