-
JAP 활용 (1-4) : 변경 감지와 병합카테고리 없음 2024. 1. 4. 16:12
1. 준영속 엔티티
영속성 컨텍스트가 더는 관리하지 않는 엔티티를 의미
(DB에서 em.find등으로 꺼낸게 아니라, 엔티티를 new해서 만든것 -> DB에 이미 저장되어서 식별자가 존재하지만, 영속성 관리 안해주는 것)
2 준영속 엔티티를 수정하는 2가지 방법
> 변경 감지 기능 사용
> 병합 사용
2.1 변경 감지 기능 사용
@Transcational void update(Item itemParam) { //준영속 엔티티가 넘어옴 Item findItem = em.find(Item.class,itemPAram.getId()) //영속으로 관리되는 엔티티 조회 findItem.setPrice(itemParam.getPrice()) // 이를 통해 데이터 수정 }
- 영속성 컨텍스트에서 엔티티를 조회한 후에 데이터 수정하는 방법
- 트랜잭션 안에서 엔티티를 다시 조회, 변경할 값 선택 -> 트랜잭션 커밋 시점에 변경 감지 동작해서 데이터 베이스에
UPDATE SQL 실행
2.2 병합 사용
병합 준영속 상태의 엔티티를 영속 상태로 변경할 때 사용하는 기능이다.
@Transactional void update(Item itemParam) { //itemParam: 파리미터로 넘어온 준영속 상태의 엔티티 Item mergeItem = em.merge(itemParam); }
- > 병합 동작 방식
1. merge()를 실행한다.
2. 파라미터로 넘어온 준영속 엔티티의 식별자 값으로 1차 캐시에서 엔티티를 조회한다.
> 만약 1차 캐시에 엔티티가 없으면 데이터 베이스에서 엔티티 조회, 1차 캐시에 저장함
> 조회한 영속 엔티티에 member엔티티의 값을 채워 넣음
> 영속 상태인 mergeMember를 반환함
정리하자면, 준영속 엔티티의 식별자 값으로 영속 엔티티를 조회한다.
영속 엔티티의 값을 준영속 엔티티의 값으로 모두 교체한다.(병합한다)
트랜잭션 커밋 시점에서 변경 감지 기능이 동작해서 데이터 베이스에서 UPDATE SQL이 실행
주의: 변경 감지 기능을 사용하면 원하는 속성만 선택해서 변경할 수 있지만, 병합을 사용하면 모든 속성이 동시에 변경됨
null로 업데이트 할 위험이 있다.
* 식별자(@GeneratedValue 선언)없이 persist()호출시 식별자 값이 자동으로 할당된다. 식별자를 직접 할당하도록 @Id만 선언했다면, 식별자를 직접할당하지 않고, 식별자 없는 상태로 persist()호출 -> 식별자가 없다는 예외 발생
3. 좋은 해결 책
엔티티를 변경할 때는 항상 변경 감지 사용하자
> 어설프게 엔티티 생성금지
> 트랜잭션이 있는 서비스 계층에 식별자와 변경할 데이터 명확하게 전달할 것
> 트랜잭션이 있는 서비스 계층에서 영속 엔티티 조회하고, 엔티티의 데이터 직접 변경할 것
> 트랜잭션 커밋 시점에 변경 감지 실행됨
* 또한 Setter 되도록 사용하지말고, 관련 메서드를 따로 만드는 것이 좋다.> 변경을 감지하기 쉬워진다.