백엔드/Spring

[Spring] 변경 감지 & 병합

kwang2134 2024. 9. 6. 22:19
728x90
반응형
728x90

변경 감지(Dirty Checking)

  • JPA (Java Persistence API)는 Java에서 객체와 관계형 데이터베이스 간의 매핑을 제공하는 API
  • JPA가 엔티티 객체의 상태를 자동으로 추적하고, 객체의 상태가 변경되었는지 여부를 감지하는 기능
  • EntityManager의 flush() 메서드를 호출할 때 작동

동작 방식

  • 상태 추적
    • JPA는 엔티티의 최조 상태를 스냅샷으로 저장
    • 스냅샷은 1차 캐시에 저장되고 엔티티의 원본 상태를 나타냄
  • 변경 감지
    • EntityManager의 flush() 메서드가 호출되면 JPA는 현태 엔티티 상태와 스냅샷을 비교
    • 엔티티 객체의 필드가 변경된 것이 감지되면 JPA는 SQL UPDATE 쿼리로 변환
  • 자동 동기화
    • flush() 메서드가 호출되면, JPA는 감지된 모든 변경 사항을 데이터베이스에 반영
    • 트랜잭션이 커밋될 때도 자동으로 발생

장단점

  • 장점
    • 직접 쿼리를 작성하거나 상태를 수동으로 동기화할 필요가 없으므로 코드가 더 간결해짐
    • 데이터베이스와 자바 객체 간의 상태 일관성을 자동으로 유지할 수 있음
    • 트랜잭션이 커밋될 때 변경된 내용이 자동으로 데이터베이스에 반영되므로 트랜잭션 관리 용이
    • JPA는 변경된 데이터만 데이터베이스에 반영 -> 전체 엔티티를 업데이트하는 것보다 성능이 좋음
  • 단점
    • 변경 감지 기능이 활성화되면 엔티티의 모든 필드에 대해 변경 여부를 체크 -> 엔티티가 많은 경우 성능 저하
    • 엔티티의 상태가 자동으로 동기화되어 언제 어떤 상태를 데이터베이스에 반영할지 세밀하게 제어하기 어려움

성능 최적화

  • @DynamicUpdate 어노테이션 사용 시 변경된 필드만 update 쿼리에 포함시켜 성능 향상

병합(Merge)

  • 관리되고 있지 않은 엔티티(준영속) 객체를 데이터베이스와 동기화하는 기능
  • 일반적으로 다른 세션이나 트랜잭션에서 가져온 엔티티 객체를 데이터베이스에 반영할 때 사용

동작 방식

  1. EntityManager의 merge() 호출
  2. 파라미터로 넘어온 준영속 엔티티의 식별자 값으로 1차 캐시에서 엔티티를 조회
  3. 1차 캐시에 엔티티가 없으면 데이터베이스에서 엔티티를 조회하고, 1차 캐시에 저장
  4. 조회한 영속 엔티티에 파라미터로 넘어온 값을 채워 넣음
  5. 복사된 영속 엔티티 반환

장단점

  • 장점
    • detached(준영속) 상태로 존재하던 엔티티를 쉽게 데이터베이스와 동기화할 수 있음
    • 직접 merge() 메서드를 호출하여 언제 데이터를 동기화할지 명시적으로 제어할 수 있음
    • 병합을 통해 변경할 엔티티의 범위를 명확히 지정할 수 있음
  • 단점
    • 복잡한 객체 그래프와 연관된 엔티티들을 처리할 때 복잡성이 증가 -> 새 엔티티를 반환하기 때문에 원본 엔티티와 일관성 유지가 어려움
    • 대량의 엔티티를 병합할 때 성능 문제가 발생 -> merge() 호출 시 데이터베이스에 많은 업데이트 발생 가능
    • 의도치 않은 상태 변경이나 동기화 문제

병합 전략

  • MERGE: merge()를 사용한 방법으로 엔티티의 모든 필드를 업데이트
  • UPDATE: 변경된 필드만 업데이트
  • REPLACE: 기존 엔티티를 삭제하고 새로운 엔티티로 대체

준영속 상태 (Detached state)

  • 엔티티 객체가 데이터베이스와의 연결이 끊어졌지만, 이전에 EntityManager에 의해 관리되었던 상태

영속 엔티티(Persistent Entity)

  • EntityManager에 의해 관리되고 있는 데이터베이스와 연결된 상태
  • EntityManager를 통해 데이터베이스에서 엔티티를 가져오는 경우

준영속 엔티티(Detached Entity)

  • 데이터베이스와 연결되어 EntityManager에 관리되었던 상태 -> 현재는 연결이 끊어짐
  • EntityManager를 통해 데이터베이스에서 가져온 엔티티의 정보로 새로운 객체를 만든 경우
  • 객체의 정보는 EntityManager가 관리하는 영속 엔티티와 같지만 별도의 객체가 됨
  • EntityManager에 의해 관리되지 않아 변경 감지가 일어나지 않음

준영속 엔티티 수정

  • 준영속 상태의 엔티티를 다시 영속성 컨텍스트에서 조회하여 EntityManager가 관리하는 영속 엔티티를 수정 -> 변경 감지
  • merge() 사용-> 반환값이 영속 엔티티

사용 구분

  • 변경 감지: 같은 트랜잭션 내에서 엔티티를 수정할 때 주로 사용
  • 병합: 분리된 엔티티를 다시 영속 상태로 만들 때 사용

성능

  • 변경 감지는 메모리 상의 비교만으로 작동 가능
  • 병합 사용 시 무조건 데이터베이스의 조회가 발생

병합 사용 시 문제점

  • merge() 호출 시 모든 필드가 파라미터로 넘어온 준영속 엔티티 값으로 바뀜
  • 일부 변경이 없어야 할 필드가 null이 되거나 의도치 않은 값 변경이 있을 수 있음

 

실전! 스프링 부트와 JPA 활용1 - 웹 애플리케이션 개발 강의 | 김영한 - 인프런 (inflearn.com) 강의 내용 참고

 

 

 

728x90

'백엔드 > Spring' 카테고리의 다른 글

[Spring] 영속성 컨텍스트 (Persistence Context)  (0) 2024.09.08
[Spring] JPA 개요  (1) 2024.09.07
[Spring] 스프링 트랜잭션 전파 Propagation  (0) 2024.09.05
[Spring] 스프링 트랜잭션  (0) 2024.09.04
[Spring] MyBatis  (1) 2024.09.01