Open joont92 opened 5 years ago
그러므로 CascadeType.PERSIST를 사용하고자 할 경우 삭제하는 order에 맞춰 orderList에서 요소를 삭제해주거나,
이건 deleteTest에서 이미 수행하고 있는 것 아닌가?
em.remove로 삭제한 엔티티는 member의 orderList에서 제거해줘야한다는 뜻입니다. 그렇지 않으면 CascadeType.PERSIST 때문에 남아있는 member의 orderList들에게 persist operation이 수행되게 되고, 결과적으로 delete가 씹히게 됨
내 질문이 잘못됐네 ㅎㅎㅎ 이해했습니다
와.. 쓰다가 다 날라가서 다시씀..............
엔티티의 자식에 CascadeType.PERSIST를 지정할 경우 JPA에서 추가적으로 수행하는 동작이 있고,
이 때문에 예상치 못한 사이드 이펙트가 발생할 수 있으므로 이를 남겨두고자 한다.
일단 기본적으로 cascade(영속성 전이)는 간단하다.
EntityManager를 통해
영속성 객체에 수행하는 행동이 자식까지 전파
되는 것이다.변경 감지에서의 CascadeType.PERSIST
근데 여기 JPA 2.2 specification 문서의 3.2 장
Entity Instance's Life Cycle
에 변경감지 부분인 3.2.4 Synchronization to the Database에 보면 아래와 같은 내용이 추가적으로 있음을 볼 수 있다.이 특징을 기반으로 아래의 행위들을 설명할 수 있다.
Member와 Order의 관계는 아래와 같다고 가정한다.
member를 persist할 때 order1, order2 까지 연쇄적 persist가 발생하고,
트랜잭션이 끝나고 flush 될 때 자식들에 대해 다시 persist operation을 수행하게 된다.
spec에 보면 persist operation은 아래와 같다.
즉 member의 orderList 3개에 대해 모두 persist operation이 발생하고,
앞의 2개는 이미 존재하던 것이므로 무시되고, 마지막 order3는 추가적으로 insert 되는 것이다.
CascadeType.PERSIST 이므로 em.merge 할 때 자식까지 연쇄적으로 merge가 발생하지는 않는다.
하지만 flush 될 때 CascadeType.PERSIST에 의해 member 3개에 대해 모두 persist operation이 발생한다.
이 또한 flush 될 떄 CascadeType.PERSIST에 의해 자식 order1, order2에 대해 persist operation이 수행된다.
즉 모든 행위는
flush의 CascadeType에 대한 특징
때문이다.이러한 특징으로 봤을때, 우리가 의문을 가졌던 아래 코드 또한 설명이 된다.
반면에
CascadeType.MERGE
의 경우 flush와 관련이 없기 떄문에,em.merge
메서드에 전달한 엔티티까지만 연쇄적으로 merge가 되고, 아래는 그냥 무시되었던 것이다.persist operation의 대상
위에서 언급했다시피 CascadeType.ALL, CascadeType.PERSIST 어노테이션이 추가된 자식에 대해 모두 persist operation을 발생시킨다. (소스를 정확히 본것은 아니므로 틀릴 수 있음)
그러므로 아래의 두 코드에서 발생하는 insert가 동일하게 된다.
첫번쨰의 경우 총 7개의 order에 대해 persist operation을 수행하여 5개는 무시되고, 2개가 insert 된것이고,
두번쨰의 경우 clear로 날려버렸기 때문에 총 2개의 order에 대해 persist operation이 수행되어 2개가 insert 된 것이다.(기존에 있던 것을 삭제하고 싶으면
orphanRemoval = true
를 줘야한다)그러므로 위의 두 행위는 결과적으로 데이터베이스에 동일한 행위를 수행하게 되는 것이다.
예상치 못한 동작
(지금은 예제가 간단하지만, 위와 같은 상황은 얼마든지 나올 수 있음)
order가 삭제될 것이라고 예상할 수 있지만, flush시에 orderList에 남아있는 모든 order에 대해 persist 연산을 수행하므로 결과적으로 delete 메서드가 날라가지 않는 현상이 발생한다.
그러므로
CascadeType.PERSIST
를 사용하고자 할 경우 삭제하는 order에 맞춰 orderList에서 요소를 삭제해주거나,orphanRemoval = true
를 사용해 orderList에서 삭제되면 자동으로 delete 가 날라가게끔 해야한다.이상한 부분이나 궁금하신 부분 있으면 피드백 부탁드립니다.