본문 바로가기
IT/Java

JPA 더티체킹(Dirty Checking) 이란?

by 성준하이 2022. 12. 3.
반응형

JPA에 대해서는 아래 참고 포스팅을 참고하면 확인해 볼 수 있다.

 

이번 포스팅에서 다뤄볼 내용은 더티체킹이라는 개념이며 직역으로는 변경상태 감지라고 느낄 수 있다.

 

JPA에서는 값을 데이터베이스와 영속시키기 위한 몇가지 방법이 있는데 지금까지 다뤄왔던 방법은 

merge 방법이다.

 

findbyid 로 값을 가져온 뒤 영속을 시켜둔 상태에서 필요시마다 save 메서드를 날리면서

id 값 기준으로 동일한 값이 있는지 체킹하고 있다면 update 없다면 insert를 날려주는 방식이다.

 

하지만 그렇게 되면 매번 쿼리를 날릴때마다 select insert / select update를 날리게 된다.

불필요한 데이터베이스 체킹이 한번씩 더 날아간다.

이럴 경우를 방지하려면 더티체킹이 돼야 한다.

 

간단하게 말하면 디비에 왔다 갔다 하는 방법을 맨 처음 영속할 때 한번, 그리고 모든 프로세스가 종료될 때 한번

이렇게 두 번만 하려고 하는 것이다.

 

그러기 위해서는 해당 메서드를 @Transational 어노테이션으로 묶어줘야 하고 

그러면 jpa에서의 1차 캐싱 부분에 값을 계속 저장하고 변경하면서 마지막 commit 시점에 flush를 날려준다고 생각하면 된다.

 

만약 엔티티의 칼럼이 너무 많을 경우엔 update를 필요하고 변경된 부분만 날릴 수가 있는데 이 방법은

entity class에 @DynamicUpdate라는 어노테이션을 추가해 주면 된다.

 

예제.

public String testJpa(String id) {
    Optional<TestTable> enttList = repo.findById(id);
    TestTable dto = enttList.get();

    dto.setFctr1("40");
    System.out.println("++++++++++++++++");

}

이와 같은 함수가 있다고 하자.

테스트해볼 경우의 수는 3가지이다.

1. 현재 코드 그대로 테스트

2. 현재 코드에서 @Transactional 어노테이션만 추가 후 테스트

3. 현재코드에서 System 출력 이전과 이후에 각각 repository.save(dto); 코드 추가해서 save 함수 집어넣기.
    (repository는 코드 위에 선언되어 있다고 가정)

 

결과는 아래와 같다.

번호 코드 결과 / 출력 코드
1 public String testJpa(String id) {
    Optional<TestTable> enttList = repo.findById(id);
    TestTable entity= enttList.get();

    entity.setFctr1("40");
    System.out.println("++++++++++++++++");

}
++++++++++++++++
만 출력.
코드 update 안됨.
2 @Transactional
public String testJpa(String id) {
    Optional<TestTable> enttList = repo.findById(id);
    TestTable entity = enttList.get();

    entity.setFctr1("40");
    System.out.println("++++++++++++++++");

}
++++++++++++++++
후 update query 전송
3 public String testJpa(String id) {
    Optional<TestTable> enttList = repo.findById(id);
    TestTable entity = enttList.get();

    entity.setFctr1("40");
    repository.save(entity);
    System.out.println("++++++++++++++++");

}
update query 전송  
++++++++++++++++
3-1 public String testJpa(String id) {
    Optional<TestTable> enttList = repo.findById(id);
    TestTable entity = enttList.get();

    entity.setFctr1("40");
    System.out.println("++++++++++++++++");
    repository.save(entity);

}
++++++++++++++++
후 update query 전송

 

1번의 경우는 save로 저장도 없고 Transactional로 묶이지 않아서 아무리 entity가 변했다 한들 쿼리가 날아가지 않아 종료가 되는 케이스이다.

2번의 경우는 Transactional 로 묶여있기에 묶인 메서드가 종료될때 commit이 되기에 종료 직전 print를 찍고 update가 이뤄진다.

3번과 3-1의 경우에 일단 entity 는 setter 를 지양하지만, 편의상 추가하였으니 양해바란다.

Transactional 어노테이션으로 묶여있지는 않지만 실제로 commit을 위한 쿼리를 날리는 save 함수를 직접 호출했기에 결과가 위와 같다.


참고 포스팅

https://thenicesj.tistory.com/106

 

SpringBoot/JPA part.1

저번 spring/mybatis 포스팅에 이어서 이번엔 springboot/JPA 포스팅을 다뤄볼것이다. spring과 springboot는 어떤 차이가 있는지는 아래 참고 포스팅 부분을 확인해보도록 하자. 시작하기 앞서 스프링을 해

thenicesj.tistory.com

 

반응형

'IT > Java' 카테고리의 다른 글

JPA메서드 save 와 saveAndFlush 비교  (32) 2022.12.05
spring annotation-driven 시 bean name 중복(충돌,conflicts) 해결  (35) 2022.12.04
List 와 map 에 대해서  (30) 2022.12.02
자이썬(Jython) 이란?  (40) 2022.12.01
Stream 이란?  (45) 2022.11.28

댓글