본문 바로가기
Develop/Java

[JPA] 더티 체킹

by 연로그 2021. 1. 18.
반응형

(설명만 보려면 게시글 아래로)

 

게시글을 수정하는 코드를 작성하고 있다.

순서대로 Controller와 Service 코드의 일부이다.

@PutMapping("/api/v1/posts/{id}")
public Long update(@PathVariable Long id, @RequestBody PostsUpdateRequestDto requestDto) {
	return postsService.update(id, requestDto);
}
@Transactional
public Long udpate(Long id, PostsUpdateRequestDto requestDto) { 
	Posts posts = postsRepository.findById(id)
			.orElseThrow(() -> new IllegalArgumentException("해당 게시글이 없습니다. id="+id));
		
	posts.update(requestDto.getTitle(), requestDto.getContent());
	return id;
}

Service에서 posts를 통해 update를 호출했는데 이것은 내가 Posts라는 객체에서 직접 선언해준 부분이다.

public void update(String title, String content) {
	this.title = title;
	this.content = content;
}

어떤 점이 의아하냐 하면, 코드 내에서 쿼리를 날리는 부분이 없다.

 

하지만 테스트 코드를 작성해서 확인해보면 update문이 실행된 것을 확인할 수 있다.

...
@Test
public void Posts_수정() throws Exception {
	//given
	Posts	savedPosts	= postsRepository.save(Posts.builder()
		.title("title")
		.content("content")
		.author("author")
		.build());

	Long	updateId 	= savedPosts.getId();
	String	expectedTitle	= "title!!";
	String	expectedContent	= "content!!";
	String	url 		= "http://localhost:" + port + "/api/v1/posts/" + updateId;

	PostsUpdateRequestDto requestDto = PostsUpdateRequestDto.builder()
		.title(expectedTitle)
		.content(expectedContent)
		.build();

	HttpEntity<PostsUpdateRequestDto> requestEntity = new HttpEntity<>(requestDto);

	//when
	ResponseEntity<Long> responseEntity = restTemplate
		.exchange(url, HttpMethod.PUT, requestEntity, Long.class);

	//then
	assertThat(responseEntity.getStatusCode()).isEqualTo(HttpStatus.OK);
	assertThat(responseEntity.getBody()).isGreaterThan(0L);

	List<Posts> all = postsRepository.findAll();
	assertThat(all.get(0).getTitle()).isEqualTo(expectedTitle);
	assertThat(all.get(0).getContent()).isEqualTo(expectedContent);

}
...

 

이는 Dirty Checking 덕분인데, 상태 변경 검사 정도로 이해하면 된다.

 

JPA에서 트랜잭션이 끝나는 시점에 변화가 있는 모든 엔티티 객체를 db에 자동으로 반영해준다.

(변화가 있다의 기준: 최초 조회 상태)

 

JPA에서는 엔티티를 조회하면 해당 엔티티의 조회 상태 그대로 스냅샷을 만들어둔다.

트랜잭션이 끝나는 시점에 이 스냅샷과 비교하고 다른 점이 있다면 Update Query를 db로 전달한다.

 

이런 Dirty Checking의 대상은 '영속성 컨텍스트가 관리하는 엔티티'만 적용된다.

detach된 엔티티(준영속), db 반영 전의 첫 생성 엔티티(비영속) 등의 엔티티는 적용 대상이 아니다.

(=값을 변경해도 db에 반영되지 않는다)

 

Dirty Checking의 update 쿼리는 모든 필드 업데이트가 디폴트다.

변경 부분만 update하고 싶다면 엔티티 최상단에 @DynamicUpdate를 선언해주면 된다.

 


참고

- 스프링 부트와 AWS로 혼자 구현하는 웹 서비스 / 이동욱

- jojoldu.tistory.com/415

반응형