일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | ||||
4 | 5 | 6 | 7 | 8 | 9 | 10 |
11 | 12 | 13 | 14 | 15 | 16 | 17 |
18 | 19 | 20 | 21 | 22 | 23 | 24 |
25 | 26 | 27 | 28 | 29 | 30 | 31 |
- deque
- 비트 연산자
- 프로그래머스
- 논리 연산자
- 누적합
- Union
- 코딩교육
- SSAFY
- 연산자 우선순위
- 산술 연산자
- prefix sum
- 순위함수
- 서로소집합
- SSAFY웰컴킷
- unionfind
- 덱
- 삼항 연산자
- SWEA
- Java
- 삼성청년SW아카데미
- linkedlist
- 알고리즘
- 자바 연산자
- SSAFY입학
- 비교 연산자
- 연결리스트
- 내부반복
- 자료구조
- rank
- Stream
- Today
- Total
개발하는 몽당연필
더티 체킹 (Dirty Checking) 본문
JPA와 같은 ORM 구현체 개발 시에 더티 체킹이라는 말을 자주 볼 수 있습니다.
더티 체킹에 대해 더 자세히 정리해보겠습니다 ❕
📌 더티 체킹 (Dirty Checking) 이란?
트랜잭션 안에서 Entity의 변경이 일어났을 때,
변경한 내용을 자동으로 DB에 반영하는 것
더티 체킹의 뜻은 변경 감지 정도로 생각할 수 있습니다.
즉, 변경을 감지해서 DB에 반영합니다.
정확한 동작 방식을 설명하기 위해서 Spring Data JPA가 아닌 네이티브한 코드를 살펴보겠습니다.
@Slf4j
@RequiredArgsConstructor
@Service
public class PayService {
public void updateNative(Long id, String tradeNo) {
EntityManager em = entityManagerFactory.createEntityManager();
EntityTransaction tx = em.getTransaction();
tx.begin(); //트랜잭션 시작
Pay pay = em.find(Pay.class, id);
pay.changeTradeNo(tradeNo); // 엔티티만 변경
tx.commit(); //트랜잭션 커밋
}
}
코드를 보면 별도로 데이터베이스에 save 하지 않는 것을 볼 수 있습니다.
- 트랜잭션 시작
- 엔티티 조회
- 엔티티 값 변경
- 트랜잭션 커밋
이 과정 중 DB에 update
쿼리에 관한 코드는 어디에도 없습니다.
이 코드가 어떻게 작동하는지 테스트 코드를 작성해보겠습니다.
@RunWith(SpringRunner.class)
@SpringBootTest
public class PayServiceTest {
@Autowired
PayRepository payRepository;
@Autowired
PayService payService;
@After
public void tearDown() throws Exception {
payRepository.deleteAll();
}
@Test
public void 엔티티매니저로_확인() {
//given
Pay pay = payRepository.save(new Pay("test1", 100));
//when
String updateTradeNo = "test2";
payService.updateNative(pay.getId(), updateTradeNo);
//then
Pay saved = payRepository.findAll().get(0);
assertThat(saved.getTradeNo()).isEqualTo(updateTradeNo);
}
}
위 테스트 코드를 수행하면, 아래와 같은 로그를 확인할 수 있습니다.
save 메서드로 변경 사항을 저장하지 않았음에도 update 쿼리가 실행된 것을 확인할 수 있습니다.
즉, JPA에서는 트랜잭션이 끝나는 시점에 변화가 있는 모든 엔티티 객체를 데이터베이스에 자동으로 반영해주는데, 이를 더티 체킹 (Dirty Checking) 이라고 합니다.
(이때 변화가 있다의 기준은 최초 조회 상태)
여기서 Dirty란 상태의 변화가 생긴 정도로 이해할 수 있으며, Dirty Checking 이란 상태 변경 검사를 의미합니다.
📌 더티 체킹의 기준
더티 체킹에서 "변화가 있다"의 기준은 최초 조회 상태입니다.
JPA에서는 엔티티를 조회하면 해당 엔티티의 조회 상태 그대로 스냅샷(snapshot)을 만들어 놓습니다.
그리고 트랜잭션이 끝나는 시점에는 이 스냅샷과 비교해서 변경점이 있다면 Update Query를 데이터베이스로 전달합니다.
당연히 이러한 상태 변경 검사의 대상은 영속성 컨텍스트가 관리하는 엔티티에만 적용됩니다.
- Detach된 엔티티 → 준영속
- DB에 반영되기 전 처음 생성된 엔티티 → 비영속
등 준영속 / 비영속 상태의 엔티티는 더티 체킹 대상에서 제외됩니다.
즉, 값을 변경해도 데이터 베이스에 반영되지 않는다는 것 입니다.
📌 Spring Data JPA의 더티 체킹
위의 네이티브 코드를 Spring Data JPA와 @Transactional 어노테이션이 함께할 경우엔 다음과 같습니다.
@Slf4j
@RequiredArgsConstructor
@Service
public class PayService {
private final PayRepository payRepository;
@Transactional
public void update(Long id, String tradeNo) {
Pay pay = payRepository.getOne(id);
pay.changeTradeNo(tradeNo);
}
}
그리고 테스트 코드를 작성해보겠습니다.
@Test
public void SpringDataJpa로_확인() {
//given
Pay pay = payRepository.save(new Pay("test1", 100));
//when
String updateTradeNo = "test2";
payService.update(pay.getId(), updateTradeNo);
//then
Pay saved = payRepository.findAll().get(0);
assertThat(saved.getTradeNo()).isEqualTo(updateTradeNo);
}
위의 테스트 코드를 수행하면, 아래와 같이 정상적으로 update 쿼리가 수행됨을 확인할 수 있습니다.
📌 변경 부분만 update 하고 싶다면? @DynamicUpdate
Dirty Checking으로 생성되는 update 쿼리는 기본적으로 모든 필드를 업데이트 합니다.
JPA에서는 전체 필드를 업데이트하는 방식을 기본값으로 사용합니다.
전체 필드를 업데이트하는 방식의 장점은
- 생성되는 쿼리가 같아 부트 실행시점에 미리 만들어서 재사용이 가능합니다.
- 데이터베이스 입장에서 쿼리 재사용이 가능합니다.
(동일한 쿼리를 받으면 이전에 파싱된 쿼리를 재사용)
하지만, 필드가 20~30개 이상인 경우엔 이런 전체 필드 update 쿼리가 부담스러울 수 있습니다.
사실 이런 경우는 정규화가 잘못된 경우일 확률이 높습니다.
한 테이블에 필드 30개는 확실히 많습니다.
현재 운영중인 정산 서비스에는 데이터 양이나 복잡도가 국내에서 손꼽히지만 15개 넘는 필드를 가진 테이블은 없습니다.
그래서 이런 경우에는 @DynamicUpdate 어노테이션으로 변경 필드만 반영되도록 할 수 있습니다.
엔티티 최상단에 아래 코드와 같이 @DynamicUpdate 를 선언해주시면 됩니다.
@Getter
@NoArgsConstructor
@Entity
@DynamicUpdate // 변경한 필드만 대응
public class Pay {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String tradeNo;
private long amount;
}
그리고 다시 테스트 코드를 수행해서 로그를 확인해보면
변경된 부분 (trade_no) 만 update 쿼리에 반영된 것을 확인할 수 있습니다.
📖 Reference
더티 체킹 (Dirty Checking)이란?
Spring Data Jpa와 같은 ORM 구현체를 사용하다보면 더티 체킹이란 단어를 종종 듣게 됩니다. 더티 체킹이란 단어를 처음 듣는분들을 몇번 만나게 되어 이번 시간엔 더티 체킹이 무엇인지 알아보겠습
jojoldu.tistory.com
- https://github.com/gyoogle/tech-interview-for-developer/blob/master/Web/Spring/%5BSpring%20Data%20JPA%5D%20%EB%8D%94%ED%8B%B0%20%EC%B2%B4%ED%82%B9%20(Dirty%20Checking).md