어 나 갱수.

[JPA] 더티 체킹 (Dirty Checking) 본문

JPA

[JPA] 더티 체킹 (Dirty Checking)

김경수 2024. 8. 9. 22:22
728x90

JPA를 사용하다 보면 더티 체킹이라는 말을 많이 듣게 됩니다.

 

대부분의 ORM에서는 기본적으로 CRUD 기능을 제공합니다. JPA에서는 find(조회), persist(저장), remove(삭제)가 있습니다.
그러나 변경에 대한 메서드는 제공하지 않습니다.

 

JPA에서 수정에 대한 기능을 제공하기 위해서 더티 체킹이라는 것을 제공해 줍니다.

 

더티 체킹을 간단하게 말하면 하나의 Transaction안에서 엔티티에 변경사항이 생기면 변경사항을 자동으로 데이터베이스에 반영해 주는 기능입니다. 

 

@Transactional
override fun execute(updatePasswordRequest: UpdatePasswordRequest) {
    val accountIdx = accountUtil.getCurrentAccountIdx()
    val account = accountRepository.findByIdOrNull(accountIdx)
        ?: throw AccountNotFoundException()
    if (!passwordEncoderPort.isPasswordMatch(updatePasswordRequest.password, account.password)) {
        throw PasswordNotMatchException()
    }

    account.updatePassword(passwordEncoderPort.passwordEncode(updatePasswordRequest.newPassword))
}

 

위에 코드에서는 Transaction 어노테이션을 통해 Trasaction을 실행시키도록 하였습니다. 위와 같이 Transaction을 실행시키면 변경된 entity를 save 하는 코드가 없어도 update 쿼리문이 발생해서 수정 기능을 구현할 수 있습니다. 이때 변화된다는 엔티티의 기준은 트랜잭션이 처음 시작됐을 때 기준입니다.
JPA에서는 트랜잭션이 시작되고 컨텍스트 내에서 최초 조회 시의 엔티티에 대한 스냅샷을 보관합니다. 그리고 트랜잭션을 커밋 시 EntityManager가 flush 명령어를 수행할 때, 스냅샷과 Entity를 비교합니다. 변경된 내용이 있으면 쓰기 지연 SQL 저장소에 update 쿼리문을 저장합니다. 
이렇게 트랜잭션이 끝난 시점에 변화가 있는 모든 엔티티 객체를 데이터베이스에 자동으로 반영해 줍니다.

Dirty Checking 작업은 이미 영속화된 엔티티들을 대상으로만 작동합니다. 띠라서 준영속상태이거나 비영속상태인 엔티티들은 JPA에서 Dirty Checking을 진행하지 않습니다.

위와 같이 update 쿼리문이 발생합니다.

모든 필드에 대해 update 쿼리문이 발생하는 이유

위의 update 쿼리문을 보게 되면 모든 필드에 대해 update 쿼리문이 발생한다. 이렇게 모든 필드에 대해 update 쿼리를 날리면 DB에 보내는 데이터 전송량이 증가한다. 그럼에도 이렇게 모든 필드에 대해 update 쿼리문을 날렸을 때의 장점이 존재한다.
update 쿼리문을 위와 같이 모든 필드에 대해 날리게 된다면 변경되는 필드에 상관없이 항상 동일한 update 쿼리문을 발생시키기 때문이다. 그 말인 즉슨, update 쿼리문을 미리 만들어 놓고 재사용가능하다는 것입니다.

JPA에서는 애플리케이션 로딩 시점에서 update 쿼리문을 미리 생성해두고 재사용 가능하게 합니다. DB에서도 동일한 쿼리에 대해 이전에 파싱 된 쿼리를 재사용할 수 있습니다.

여기서 모든 필드를 변경하는 것이 아니라 원하는 필드만 변경하게 하려면 @DynamicUpdate 어노테이션을 사용할 수 있습니다.

위와 같이 엔티티에 @DynamicUpdate 어노테이션을 붙이게 되면 아래와 같이 update 쿼리가 발생할 때 모든 필드에 대해 발생하지 않고 변경되는 해당 필드에 대한 update 쿼리문만 발생하게 됩니다.

 

 

728x90