본문 바로가기

강의 내용 정리/스프링부트와 JPA 활용 1

7-7. 변경 감지와 병합(merge)(정말 중요)(정말 중요)(정말 중요)

# 영속성 컨텍스트

엔티티가 영속상태로 관리가 되면 , 거기있는 값만 바꾸면 JPA가 트랜젝션 commit 시점에 flush하여 변경된 내용을 DB에 반영해줌.

 

 

시험삼아 만들어본 ItemUpdateTest.java

 

 

Book을 가져온 후 트랜젝션 안에서는 setName으로 이름 바꾼 후 트랜젝션이 commit되면 JPA가 변경분을 자동으로 찾아서 UPDATE 쿼리를 자동생성해서 DB에 반영함 -> 변경감지 = dirty checking ( JPA의 기능 )

 

 

 

예를 들면

Order.java

여기서 처럼 Order의 Status 를 바꿔 줬음에도 불구 하고 따로 DB에 UPDATE 쿼리를 날리는 코드는 없다.(em.update 나 em.merge 없었다. )

-> 영속상태인 엔티티의 값을 바꿔놓으면 JPA가 트랜잭션 커밋 시점에 변경감지하여 DB에 UPDATE문 날리고 트랜젝션 커밋함. 

-> 값을 바꿔놓으면 JPA가 트랜잭션 커밋 시점에 변경감지하여 DB에 UPDATE문 날리고 트랜젝션 커밋함. 

 

 

 

 

====================================================== 준영속 엔티티

 

 

ItemController.java

예를 들면 여기서의 Book 객체가 객체는 새로운 객체인데 Id가 세팅이 되어있다. -> JPA에 한 번은 들어갔다 나온 객체이다 -> 위의 Book 객체는 준영속 엔티티.

( 식별자가 정확히 DB에 있으면 준영속 엔티티라고 함. ) = 영속성 컨텍스트가 더는 관리 하지 않는 엔티티.=JPA가 더는 관리 안함

 

준영속 엔티티(Book)의 문제점 : JPA가 관리 안함.

 

-> JPA가 관리하는 영속상태 엔티티는 변경감지가 일어남. ( JPA가 보고있음 ) -> 그래서 트랜젝션 커밋 시점 직전에 변경된 것을 바꿔줌.

 

일단 여기서 Book 객체는 내가 new해서 만든것이므로 JPA가 관리 안함. -> 아무리 Book에다가 값을 바꿔도 DB에 UPDATE가 안 일어남. ( Transaction 이 있다해도 JPA가 관리 안하기 떄문에 자동으로 UPDATE 해줄 수도 없다. )

 

<이 부분 다시 듣자. 이해가 안된다.>

=> 그렇다면 이런 준영속 엔티티의 데이터를 변경할 수 있을까?

 

https://www.inflearn.com/questions/70393

 

book 객체가 왜 준영속인것인가 - 인프런 | 질문 & 답변

[사진] 수정을 시도하는 Book객체는 새로 만들어진것이잖아요 강사님. 이 Book객체는 이미 DB에 한번 저장이 되었다고 했는데 persist를 한적도 없고 db를 통해 find 한 객체도 아닌데 어떻게 이게 준영

www.inflearn.com

1. 준영속이지만 변경감지사용, 2. merge 사용

1. 

 

ItemService.java

findOne으로 (em.find)  찾아온 객체는 영속상태이다. -> 리턴 된 findItem도 영속상태객체를 가리킨다.

 

 

 

29. itemId를 기반으로 실제 DB의 영속상태의 Item을 찾아옴.

findItem들 값 세팅

33. 여기서 findItem을 persist 해줘야 할까????????  => 필요없다.

findItem은 영속상태이다. -> 메서드가 끝나면 스프링의 @Transactional 에 의해서 열렸던 트랜젝션이 commit이 된다. commit이 되면 JPA는 flush를 한다. (flush : 영속성컨텍스트중에서 변경된 애들을 찾는다. ) -> 찾으면 바뀐 부분을 UPDATE 쿼리를 DB에 날려서 업데이트한다.  ( 이게 맞음 )

 

 

이제 보인 건데 Service 클래스에는 항상 @Transactional 이 붙어있다. ( 클래스단위에 readOnly true 해주자. 값을 변경하는 메서드는 따로 @Transactional 붙여줌. ) -> Repository에 접근하는 계층이라 @Transactional 붙여줌.

 

 

 

 

 

1. Merge를 이용한 update

 

id가 있으면 em.merge(item)을 한다.

 

 

param으로 넘어온 Book객체로 findItem을 찾고 JPA가 findItem 에  param의 모든 데이터를 바꿔치기해줌 -> 그 뒤 트랜젝션 커밋 될 때 변경감지기능에 이 부분이 걸려서 다 UPDATE 반영이된다. 

바꿔치기 된 객체를 반환해줌. ( 여기선 리턴 없음 ) -> JPA가 만들어 주는 것에는 있다.

 

ItemService.java
ItemRepository.java

바로 위의 saveItem을 참고하자면 save에 넘긴 item 이 em.merge(item) 될 때 JPA가 모든 데이터를 바꿔치기해줌.

 

 

이걸 보면 바꿔치기 된 객체를 반환해준다는 것을 알 수 있다. -> merge는 영속성 컨텍스트에서 관리되는 객체, 그러나 파라미터 item은 영속상태로 변하진 않음. ( 서로 다른 애 )

 

 

 

# 정리

 

ItemService.java

이 사진 다시보면 이해될듯.

위의 1,2,3번

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

Item findItem= itemRepository.findOne(param.getId());

 

2. 영속 엔티티의 값을 준영속엔티티의 값으로 모두 교체한다.(병합한다.)

findItem.set 3줄

 

3. 트랜잭션 커밋 시점에 변경감지기능이 동작해서 DB에 UPDATE 쿼리를 보낸다.

 

 

 

 

 

 

 

 

 

# 문제점.

 

null로 업데이트 될 수 있다.!!!!!!!!!! 매우 위험.

 

=> 이래서 merge 안쓰고 변경감지 쓴다. ( 실무에서도 )

 

 

 

=> 직접 영속객체를 조회한 후 업데이트 할 필드를 set, set, set.. 해서 반환해야함.

 

ItemService.java

이런식으로.

 

 

-> 여기서 중요한 점 : ItemService에서 setsetset 하지말고 메서드로 뽑아서 Item 엔티티에 넣어두자. ( 변경지점이 엔티티로 가서 좋음. ( 나중에 고칠 떄 ))

 

-> 변경사항은 엔티티에서 볼 수 있게

 

 

번외 :: 우리가 만든 BookForm 객체는 웹 계층에서만 쓰자. ( Controller, resources/templates/ )

그래서 ItemService에서 Book param 으로 받음. 

 

 

# 결론

 

완전 중요. 이번 포스트를 관통하는 주제.

 

 

ItemController.java
ItemService.java

1. 이렇게 넘겨주면 유지보수 훨씬 쉬움. ( 컨트롤러에서 어설프게 엔티티 생성안함. -> 변경감지 사용. )

2. ItemService에서 식별자와 변경할 데이터를 파라미터로 받음. ( 아니면 UpdateItemDto 만들어서 name, price,                stockQuantity 줘도됨. )

 

 

 

# 오늘의 결론 1번

 

김영한님 답변 :

트랜잭션을 커밋하게 되면 내부에서 자동으로 플러시가 호출됩니다.

그리고 플러시가 일어나야 변경감지가 동작합니다.

 

***********트랜젝션 안에서 엔티티를 조회해야 영속상태로 조회 된다. 거기에 값을 변경해야 dirty checking 이 일어난다. -> 그러면 트랜젝션이 커밋 될 때 flush가 일어나면서 변경감지된 게 UPDATE쿼리가 DB에 쫙 나간다.

 

 

 

# 오늘의 결론 2번

ItemService.java

-> 여기서 중요한 점 : ItemService에서 setsetset 하지말고 메서드로 뽑아서 Item 엔티티에 넣어두자. ( 변경지점이 엔티티로 가서 좋음. ( 나중에 고칠 떄 ))

-> 엔티티 안에서 바로 추적할 수 있는 메서드를 만들어라. 예를 들면 위의 Item엔티티클래스의 change메서드

-> 이러면 모든 변경 사항을 모아두게 되므로 change만 뒤져도 뭘 바꾸는지 알 수 있다.

Recent Posts
Popular Posts
Recent Comments