[JPA] JPA의 UPDATE방식과 Dirty Checking

chiyongs·2022년 7월 5일
2
post-thumbnail

최근 프로젝트를 진행하면서 게시글을 수정하는 메소드에 대해 리팩토링을 진행하였습니다.
리팩토링 PR에 대해 한 팀원분께서 comment를 남겨주셨는데 내용은 다음과 같습니다.

PR 질문

해당 상황에 대한 이해를 돕기 위해 게시글 수정 메소드를 가져왔습니다.

// 원본 코드를 예시용으로 간단하게 바꿨습니다.
@Transactional
public Long modifyArticle(Long articleId, ArticleRequest articleRequest) {
	Article article = articleRepository.findById(articleId)
						.orElseThrow(() -> new CustomException(ErrorCode.ARTICLE_NOT_FOUND, articleId.toString()));
	article.modifyArticle(articleRequest);
    return articleId;
}

팀원분의 질문처럼 해당 modifyArticle메서드에서는 수정된 게시글을 저장하는 save메소드를 사용하지 않고 있습니다.
그렇다면 어떻게 수정된 게시글이 저장되는 걸까요??

먼저, JPA에서 Update가 어떻게 진행되는지 알아보겠습니다.

대부분의 ORM들은 CRUD를 지원합니다. JPA에서는 find(조회), persist(저장), remove(삭제)가 있습니다.
하지만, 변경(Update)에 대한 메소드가 존재하지 않습니다.
왜 그럴까요??
그 이유는 SimpleJpaRepository클래스의 save메소드에서 찾아볼 수 있습니다.

@Transactional
@Override
public <S extends T> S save(S entity) {

	Assert.notNull(entity, "Entity must not be null.");

	if (entityInformation.isNew(entity)) {
		em.persist(entity);
		return entity;
	} else {
		return em.merge(entity);
	}
}

save 메소드에서는 해당 엔티티가 처음 들어오는(isNew) 엔티티라면 엔티티매니저(EntityManager)를 통해 persist를 진행합니다. 그렇지 않다면(기존에 존재하던 엔티티라면), merge를 진행합니다.
따라서, JPA는 save메서드를 통해 저장과 변경에 대한 기능을 한번에 제공하고 있습니다. 덕분에 우리는 JPA를 사용하면서 update 처리를 진행하는 메소드를 따로 만들지 않아도 됩니다.

하지만 여기서 의문점이 생깁니다. 🤔

그렇다면 맨 처음 보여드린 코드에서 save메소드를 아예 사용하지 않았는데 JPA가 어떻게 엔티티의 변경을 감지하고, DB에 update 쿼리를 실행할까요??

JPA에서는 Dirty Checking을 통해 처리합니다.

Dirty Checking이란?
엔티티 매니저가 변경이 발생한 엔티티를 자동 감지하여 데이터베이스에 반영하는 것을 말합니다.

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

그렇다면, JPA는 어떻게 엔티티들의 변경을 감지할 수 있을까요??

JPA는 엔티티를 조회할 때 해당 엔티티의 상태를 기반으로 하나의 스냅샷을 만듭니다.
그 후 트랜잭션이 종료되는 시점에서 만들어놓은 스냅샷과 비교하여 변경을 감지합니다.
만약 변경이 감지되었다면, 수정(Update) 쿼리를 데이터베이스에 전달합니다.

// 원본 코드를 예시용으로 간단하게 바꿨습니다.
3. @Transactional
public Long modifyArticle(Long articleId, ArticleRequest articleRequest) {
	1. Article article = articleRepository.findById(articleId)
							.orElseThrow(() -> new CustomException(ErrorCode.ARTICLE_NOT_FOUND, articleId.toString()));

	2. article.modifyArticle(articleRequest);
        
	return articleId;
}

위 예시 코드로 보면
1. Article 엔티티를 조회할 때 Article 엔티티 상태를 기반으로 하나의 스냅샷을 만들고
2. 수정이 진행된 후
3. 트랜잭션이 종료될 때 변경이 감지되어 데이터베이스로 수정 쿼리를 전달하는 것입니다.


마무리

JPA는 update 메소드를 따로 구현하지 않고 save메소드를 통해 저장과 변경에 대한 기능을 한 번에 제공하고 있습니다.
또한, Dirty Checking을 통해 영속화된 엔티티들에 대한 변경을 자동으로 감지하여 수정 쿼리를 데이터베이스에 전달합니다.
따라서, 영속화된 엔티티라면 별도로 save메소드를 사용하지 않아도 JPA에 의해 변경 사항이 자동으로 데이터베이스에 적용됩니다.

0개의 댓글