backend/springboot

99클럽 코테 스터디 7일차 TIL - springboot 변경 감지와 병합

ssoheeh 2024. 4. 7. 18:19

영속성 컨텍스트

  • 엔티티를 관리하는 논리적인 개념
  • 어플리케이션과 DB 사이에서 객체를 보관하는 가상의 DB 같은 역할
  • 엔티티를 메모리에 저장, 엔티티의 생명주기 관리, 엔티티와 DB 간의 작업 캐시해서 처리

준영속 엔티티

  • 영속성 컨텍스트가 더는 관리하지 않는 엔티티 (DB에 한 번 갔다와서 식별자 존재)
  • 수정하는 방법 - 변경 감지 기능, 병합(merge) 사용

 

 

변경 감지 기능 사용

@Transactional
void update(Item itemParam) { //itemParam: 파리미터로 넘어온 준영속 상태의 엔티티
	Item findItem = em.find(Item.class, itemParam.getId()); //같은 엔티티를 조회한다.
	findItem.setPrice(itemParam.getPrice()); //데이터를 수정한다. 
}
  • 영속성 컨텍스트에서 엔티티를 다시 조회한 후에 데이터 수정
  • 트랜잭션 안에서 엔티티 다시 조회, 변경할 값 선택 -> 트랜잭션 커밋 시점에 변경 감지 (Dirty Checking)이 동작해서 DB에 UPDATE SQL 실행

 

Dirty Checking

  • 상태 변경 검사
  • JPA에서는 트랜잭션이 끝나는 시점에 변화가 있는 모든 엔티티 객체를 데이터베이스에 자동으로 반영
  • JPS에서는 엔티티를 조회하면 해당 엔티티의 조회 상태를 스냅샷으로 만듦
  • 트랜잭션이 끝나는 시점에 이 스냅샷과 비교해서 변경이 있으면 Update query 발생
  • dirty checking 대상은 영속성 컨텍스트가 관리하는 엔티티에만 적용
  • 준영속, 비영속 상태의 엔티티는 dirty checking 대상에 포함되지 않음

 

 

병합 사용

@Transactional
void update(Item itemParam) { //itemParam: 파리미터로 넘어온 준영속 상태의 엔티티
     Item mergeItem = em.merge(itemParam);
 }

병합은 준영속 상태의 엔티티를 영속 상태로 변경할 때 사용하는 기능

  • 준영속 엔티티의 식별자 값으로 영속 엔티티 조회
  • 영속 엔티티의 값을 준영속 엔티티의 값으로 모두 교체 (병합)
  • 트랜잭션 커밋 시점에 변경 감지 기능이 동작해서 데이터베이스에 UPDATE SQL 실행

병합의 단점

  • 병합을 사용하면 모든 속성 변경 (특정 속성 변경 불가능)
  • 병합시 값이 없으면 null로 업데이트할 위험

 

 

결론

준영속 엔티티를 변경할 때는 변경 감지를 사용하자..!

  • controller에서 엔티티 생성 금지 -> 파라미터나 DTO 이용해 서비스 계층에 데이터 전달
  • 트랜잭션이 있는 서비스 계층에서 영속 상태의 엔티티를 조회하고 엔티티의 데이터 직접 변경
  • 트랜잭션 커밋 시점에 변경 감지 실행