일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
- 좋은 코드 나쁜 코드
- 레디스 동시성
- branch 전략
- 알람 시스템
- 구현
- spring event
- 디버깅
- 트랜잭샨
- piplining
- 셀러리
- 이분탐색
- docker
- JPA
- 숫자 블록
- 쿠키
- 카카오
- 주식
- 누적합
- 백준
- prg 패턴
- 완전탐색
- 프로그래머스
- 결제서비스
- 검색어 추천
- gRPC
- AWS
- BFS
- 객체지향패러다임
- jwt 표준
- 깊게 생각해보기
- Today
- Total
코딩관계론
[JPA] Dirty checking(변경감지) vs Merge(병합) 본문
소개
JPA를 사용하다 보면 엔터티의 변경이 자동으로 데이터베이스에 업데이트되는 경우가 있고, 엔터티를 수정했지만 데이터베이스에 반영되지 않는 경우가 있습니다. 이러한 차이는 엔터티가 영속성 엔터티인지 준영속성 엔터티인지에 따라 달라집니다.
준영속성 엔터티를 데이터베이스에 반영하기 위해서는 변경 감지(DIRTY CHECKING)와 병합(MERGE) 기법이 있습니다. 이 글에서는 두 기법의 차이점을 알아보고, 어떤 방법이 더 좋은지 소개하겠습니다 (feat - 김영환 센세).
Dirty Checking(변경 감지)
엔터티의 변경 사항을 데이터베이스에 자동으로 반영하는 기능을 변경 감지라고 합니다. 중요한 점은 영속성 컨텍스트가 관리하는 영속 상태의 엔터티에만 적용된다는 것입니다.
동작 순서
- 트랜잭션을 커밋하면 플러쉬가 호출된다.
- 엔터티와 스냅샷을 비교해서 변경된 엔터티를 찾는다.
- 변경된 언테티가 씨으면 수정 쿼리를 생성해서 SQL저장소에 보냐고 데이터베이스에 보낸다
- 트렌잭션을 커밋한다
준영속성 컨텍스트를 영속성 컨텍스트로 변경하는 방법
아래 코드와 같이 식별자 값을 알고 있으니 EntityManager를 통해서 엔터티를 찾아올 수 있다.
그 후 변경 사항을 업데이트 해주면 된다.
@Transactional(readOnly = false)
public void updateItem(Long itemId, BookForm bookForm){
Item updatedItem = this.itemRepository.findOne(itemId); //영속성 엔티티
updatedItem.setName(bookForm.getName());
updatedItem.setPrice(bookForm.getPrice());
updatedItem.setStockQuantity(bookForm.getStockQuantity());
this.itemRepository.save(updatedItem);
}
Merge(병합)
준영속 상태의 엔터티를 다시 영속 상태로 변경하기 위해 병합 방법을 사용합니다. merge() 메소드는 준영속 상태의 엔터티를 받아 그 정보로 새로운 영속 상태의 엔터티를 반환합니다.
동작 순서
- merge()를 실행 & 준영속 엔터티의 식별자 값으로 1차 캐시에서 엔터티를 조회한다.
- 1차 캐시에 식별자 값이 없다면 데이터베이스에서 조회하고 1차 캐시에 업데이트를 진행한다.
- 조회한 영속엔터티에 준영속 엔터티의 값들을 채워 넣는다.
- 이후에 이 영속엔터티를 반환한다
단점
Merge 방식은 PUT 메소드와 행동 방식이 비슷합니다. 즉 부분변경이 불가능합니다.
예를 들어, B라는 클래스는 A, B, C 변수를 가지고 있고, 준영속성 엔터티에는 B, C 변수의 값만 세팅되어 있다면, Merge 방식으로 진행하면 A 변수는 NULL로 변경되고, 이 NULL 값이 데이터베이스에 저장됩니다.
결론
준영속성 엔터티의 경우 병합 기법을 사용하면 단점이 명확하므로, 이 방법을 피하고 변경 감지 기법을 사용하는 것이 좋습니다.