728x90
반응형
준영속 상태
- 영속 상태의 엔티티가 영속성 컨텍스트에서 분리된 것
- 영속성 컨텍스트가 제공하는 기능 사용 불가
- em.detach(entity)
- 특정 엔티티만 준영속 상태로 전환
- 1차 캐시에서 빠진다라고 생각하면 쉬움
- em.clear()
- 영속성 컨텍스트 완전히 초기화
- 테스트 케이스 작성시 사용
- em.close()
- 영속성 컨텍스트를 종료
준영속 엔티티
- 영속성 컨텍스트가 더는 관리하지 않는 엔티티(DB에 한번 갔다 와서 식별자가 존재)
- 변경 감지, 병합을 통해 준영속 엔티티를 수정할 수 있다.
변경 감지 기능
@Transactional
void update(Item itemParam) {
Item findItem = em.find(Item.class, itemParam.getId());
findItem.setPrice(itemParam.getPrice());
}
- 영속성 컨테스트에서 해당 id를 다시 조회한후 데이터를 수정
- 조회한 findItem은 영속상태
- 트랜잭션 안에서 엔티티를 다시 조회, 변경할 값 선택 트랜잭션 커밋 시점에 변경 감지(Dirty Checking)이 동작해서 데이터베이스에 UPDATE SQL 실행
더티 체킹(Dirty Checking)
- 상태 변경 검사
- JPA에서는 트랜잭션이 끝나는 시점에 변화가 있는 모든 엔티티 객체를 데이터베이스에 자동으로 반영
- JPA에서는 엔티티를 조회하면 해당 엔티티의 조회 상태를 스냅샷으로 만듦
- 트랜잭션이 끝나는 시점에 이 스냅샷과 비교해서 변경이 있으면 Update query 발생
- Dirty Checking 대상은 영속성 컨텍스트가 관리하는 엔티티에만 적용
- 준영속, 비영속 상태의 엔티티는 Dirty Checking 대상에 포함되지 않음
- Detech된 엔티티 - 준영속
- DB에 반영되기 전 처음 생성된 엔티티 - 비영속
- 값을 변경해도 데이터베이스에 반영되지 않음
병합
//itemParam: 파리미터로 넘어온 준영속 상태의 엔티티
@Transactional
void update(Item itemParam) {
Item mergeItem = em.merge(itemParam);
}
- merge(itemParam)를 실행
- 파라미터로 넘어온 준영속 엔티티의 식별자로 1차캐시에 조회(만약 1차 캐시에 없다면 DB에 조회후 1차캐시에 저장)
- 조회한 영속 엔티티(item)를 준영속 엔티티(itemParam) 값으로 수정
- 영속상태인 mergeItem을 반환
코드로 표현시
@Transactional
public Item update(Long itemId, Item itemParam) {
Item findItem = itemRepository.findOne(itemId);
findItem.setName(itemParam.getName());
...
return findItem;
}
병합 단점
- em.merge(itemParam) 이 코드의 경우 파라미터에 객체를 모두 보냄
- 특정 속성 변경 불가, 객체 모든 속성 변경
결론
- 준영속 엔티티를 변경할때는 항상 변경 감지를 사용
- 컨트롤러에서 엔티티 생성 금지 → 파라미터나 DTO 이용해 서비스 계층(트랜잭션)에 데이터 전달
- 트랜잭션이 있는 서비스 계층에서 영속 상태의 엔티티를 조회하고 엔티티의 데이터를 직접 변경
- 트랜잭션 커밋 시점에 변경 감지 실행
728x90
반응형
'Tech > Spring' 카테고리의 다른 글
[Spring] 스프링 빈이란? 스프링 빈 정리 (등록방식, 스코프) (0) | 2023.08.01 |
---|---|
[Spring] 스프링 주요 어노테이션, Update(수정) 시 save() 메서드를 호출하는 것이 좋을까? (2) | 2023.04.10 |
[Spring Data JPA] 스프링 테이블, 컬럼명 생성 전략 (0) | 2023.03.22 |
[Spring Data JPA] 스프링 Entity 설계 시 주의사항 (0) | 2023.03.21 |
[Spring] jasypt로 암호화하기, docker, ec2 및 CI/CD 연동하기 (0) | 2023.01.19 |