최근 프로젝트를 진행하면서 게시글을 수정하는 메소드에 대해 리팩토링을 진행하였습니다.
리팩토링 PR에 대해 한 팀원분께서 comment를 남겨주셨는데 내용은 다음과 같습니다.
해당 상황에 대한 이해를 돕기 위해 게시글 수정 메소드를 가져왔습니다.
// 원본 코드를 예시용으로 간단하게 바꿨습니다.
@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
메소드를 사용하지 않고 있습니다.
그렇다면 어떻게 수정된 게시글이 저장되는 걸까요??
대부분의 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는 엔티티를 조회할 때 해당 엔티티의 상태를 기반으로 하나의 스냅샷을 만듭니다.
그 후 트랜잭션이 종료되는 시점에서 만들어놓은 스냅샷과 비교하여 변경을 감지합니다.
만약 변경이 감지되었다면, 수정(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에 의해 변경 사항이 자동으로 데이터베이스에 적용됩니다.