[JPA] 더티 체킹(dirty checking)

해니·2023년 10월 3일
0

JPA

목록 보기
5/8
post-thumbnail



@Transactional 어노테이션을 사용하면 save 메소드를 사용하지 않아도 된다고? 🤔

JPA로 API 구현 과제를 진행 중이었는데, 지인 개발자가 위와 같은 말을 해줬다.당시에는 '그렇구나~'하고 넘어갔는데 면접에서 비슷한 질문을 받고 답변을 제대로 하지 못 해서 관련 개념을 정리해 보려고 한다.



더티 체킹(dirty checking)이란?

  • 엔티티 매니저변경이 발생한 엔티티를 자동 감지하여 데이터베이스에 반영하는 것
    • dirty는 “엔티티 데이터의 변경된 부분”을 뜻하며 dirty checking은 변경된 부분을 감지한다는 의미이다.
    • 이미 영속화된 엔티티들을 대상으로만 작동한다.
  • 영속화된 엔티티라면 별도로 save 메소드를 사용하지 않아도 JPA에 의해 변경 사항이 자동으로 데이터베이스에 적용된다.

🔎 엔티티 매니저(EntityManager)

  • 엔티티를 관리하는 역할
  • 엔티티 매니저 내부에는 영속성 컨텍스트가 있으며, 이를 통해 엔티티 관리한다.

🔎 영속성 컨텍스트

  • 엔티티를 영구 저장하는 환경을 의미
  • 애플리케이션과 DB 사이에서 객체를 보관하는 가상의 DB 역할을 한다.
  • 엔티티 매니저(EntityManager)를 통해 엔티티를 저장하거나 조회하면 엔티티 매니저는 영속성 컨텍스트에 엔티티를 보관하고 관리하게 된다.





더티 체킹의 기준

  • JPA에서는 엔티티를 조회하면 해당 엔티티의 조회 상태 그대로 스냅샷(Snapshot)을 만들어 놓는다. 그리고 트랜잭션이 끝나는 시점에는 이 스냅샷과 비교해서 다른점이 있다면 Update Query를 데이터베이스로 전달한다.
  • 이러한 상태 변경 검사의 대상은 영속성 컨텍스트가 관리하는 엔티티에만 적용된다.
  • Detach된 엔티티(준영속), DB에 반영되기 전 처음 생성된 엔티티(비영속) 등 준영속/비영속 상태의 엔티티는 더티 체킹 대상에서 제외되며, 값을 변경해도 데이터베이스에 반영되지 않는다.

🔎 스냅샷(Snapshot)

  • 영속성 컨텍스트가 생성될 때, 향후 변경 감지를 위해서 원본을 복사해서 만들어두는 객체

🔎 영속(managed)

  • 영속성 컨텍스트에 저장된 상태
  • 엔티티가 영속성 컨텍스트에 의해 관리된다.
  • 영속 상태가 되었다고 바로 DB에 값이 저장되지 않고 트렌젝션의 커밋 시점에 영속성 컨텍스트에 있는 정보들을 DB에 쿼리로 날리게 된다.
@Autowired
private EntityManager entityManager;
// Class내에 Autowired로 EntityManager추가

    // 객체만 생성한 비영속상태 (엔티티 객체를 생성하였지만 아직 영속성 컨텍스트에 저장하지 않은 상태)
    User user = new User();
    
    // 객체를 저장한 영속상태
    entityManager.persist(user);

🔎 준영속 상태(detach)

  • 영속상태의 엔티티가 영속성 컨텍스트에서 분리된 것
  • 엔티티를 준영속 상태로 만드려면 entityManager.detach()를 호출한다.
    // 영속 -> 준영속
    // user엔티티를 영속성 컨텍스트에서 분리하면 준영속 상태가 된다.
    entityManager.detach(user);
    // 영속성 콘텍스트를 비우면 관리되고 있던 엔티티들은 준영속 상태가 된다. (대기 상태에 있는 변경 데이터들도 삭제)
    entityManager.clear();
    // 영속성 콘텍스트를 종료해도 관리되던 엔티티들은 준영속 상태가 된다.
   	entityManager.close();
    
    // 준영속 -> 영속 
    // detach를 하여 준영속상태에 빠진 entity를 merge를 하면 다시 영속 상태가 된다.
    entityManager.merge(user); 





Spring Data JPA의 더티 체킹

  • Spring Data JPA에서는 @Transactional을 사용하여 더티 체킹을 수행할 수 있다.
@Service
public class ExampleService {
     @Transactional
     public void updateInfo(Long id, String name) {
          User user = userRepository.findById(id);
          user.setName(name);
     }
}




🔔 변경 부분만 update하고 싶은 경우에는?

  • JPA에서는 전체 필드를 업데이트하는 방식을 기본값으로 사용하기 때문에, 더티 체킹으로 생성되는 update 쿼리는 기본적으로 모든 필드를 업데이트한다.
  • 전체 필드를 업데이트하는 방식의 장점은 다음과 같다.
    • 생성되는 쿼리가 같아 부트 실행시점에 미리 만들어서 재사용 가능하다.
    • 데이터베이스 입장에서 쿼리의 재사용이 가능하다. (동일한 쿼리를 받으면 이전에 파싱된 쿼리를 재사용)
  • 하나의 엔티티에 필드가 많아져 update가 부담스러워지고, 변경된 필드만 upadte 쿼리로 적용하고 싶다면 @DynamicUpdate 어노테이션을 사용한다
    • 엔티티 최상단에 아래와 같이 @DynamicUpdate를 선언해주기만 하면된다.
@Getter
@NoArgsConstructor
@Entity
@DynamicUpdate // 변경한 필드만 대응
public class Pay {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String tradeNo;
    private long amount;
}











출처
[JPA] 더티 체킹(dirty checking) 정리
[JPA] JPA의 UPDATE방식과 Dirty Checking
[JPA] 더티 체킹(Dirty Checking)
더티 체킹(Dirty Checking)이란?
Jpa EntityManager 설명 (영속성 컨텍스트)
[JPA] 영속성 컨텍스트란?
[JPA] 준영속 상태(detach)
[Spring JPA] 영속성 컨텍스트(Persistence Context)
JPA 더티 체킹(Dirty Checking)이란?

profile
💻 ⚾️ 🐻

0개의 댓글