Spring

Spring Boot - 변경 감지와 병합

팅탱팅탱 2024. 3. 26. 14:57

준영속 엔티티는 영속성 컨텍스트가 더이상 관리하지 않는 엔티티를 말함.

Book객체는 이미 DB에 한번 저장되어서 식별자가 존재하는데 이렇게 임의로 만들어낸 엔티티도 기존 식별자를 가지고 있으면 준영속 엔티티라고 볼 수 있다. 

 

예시로 테스트를 하나 작성해보면 여기서 JPA에서 book 클래스를 찾아서 이름은 저렇게 바꿔주고 트렌젝션이 커밋이되면 이름이 바뀌게되는데 이게 변경 감지(더티체킹)이다. (내가 원하는 걸로 업데이트를 칠 수 있음)

 

주문 취소 로직에서도 동일하게 값을 cancle로 바꿔주는걸 해줬음.(알아서 JPA가 커밋 시점을 찾아서 DB업데이트를 해줌)

 

하지만 준영속 엔티티란 JPA의 영속성 컨텐츠가 더이상 관리를 해주지않는 상태를 말함.(영속성 엔티티는 JPA가 다 보고있어서 변경감지가 트렌젝션 커밋시점에 일어남)

 

준영속 엔티티를 변경할 수 있는 두가지 방법

1. 변경감지 기능 사용

2. 병합(merge) 사용

 

변경 감지 기능 사용

findItem으로 찾아온것은 영속 상태임. 

그럼 파라미터로 넘어온 book으로 값을 세팅을 다 했으면 스프링의 트렌젝셔널에 의해서 트렌젝션 커밋이 됨.

커밋이 되면 JPA는 플러시(영속성 컨텍스트중에 변경된 것이 뭔지 찾는것)를 날림 >  바뀐 값을 업데이트 쿼리를 날려서 DB에 업데이트를 시킴. 

 

 

병합 사용

준영속 상태의 엔티티를 영속 상태로 변경할때 사용

그냥 위에있는 코드를 한줄로 요약한것임

 

병합 동작 로직

1. merge() 실행

2. 파라미터로 넘어온 준영속 엔티티의 식별자 값으로 1차 캐시에서 엔티티 조회

2-1. 만약 1차 캐시에 엔티티가 없으면 데이터 베이스에서 엔티티를 조회하고 1차캐시에 저장.

3. 조회한 영속성 엔티티에 엔티티의 값을 채워 넣는다.

4. 영속 상태인 엔티티를 반환한다. 

 

간단히 하자면 

1. 준영속 엔티티의 식별자 값으로 영속 엔티티 조회

2. 영속 엔티티의 값을 준영속 엔티티의 값으로 모두 변경(병합)

3. 트렌젝션 커밋 시점에 변경 감지 기능이 동작해서 데이터베이스에 업데이트 sql이 실행

 

주의할점 : 변경감지 기능을 사용하면 원하는 속성만 선택해서 값을 변경 할 수 있지만 병합 기능으로 사용한다면 모든 속성이 변경됨.

병합시 값이 없으면 null로 업데이트 할 위험도 있음(병합은 모든 필드를 교체)

실무에서는 null값이 들어갈 위험도 있으니 병합보다는 변경 감지 기능을 통해 준영속 엔티티를 업데이트 하는게 좋음

(컨트롤러에서 어설프게 엔티티 생성하지 않기, 트렌젝션이 있는 서비스 계층에 식별자(id)와 변경할 데이터 명확하게 전달하기,

트렌젝션이 있는 서비스 계층에서 영속 상태의 엔티티 조회하고, 엔티티의 데이터 직접 변경하기 > 트렌젝션 커밋 시점에 변경 감지 실행)

 

컨트롤러에서 어설프게 엔티티를 생성하지 않기 위해서\

이렇게 아까 만든 업데이트item 를 사용하여서 값을 파라미터로 넘겨주었고,

업데이트 item도 값을 받아와서 바로 변경하게끔 값을 넣어주었다.

(파라미터가 많으면 새로운 DTO 클래스를 파서 값을 넣어주기)