코드 그라데이션
고아 객체, 그리고 생명 주기 본문
고아 객체
예제
Parent 수정
@OneToMany(mappedBy = "parent",cascade = CascadeType.ALL, orphanRemoval = true)
// 양방향 매핑 완료, CASCADE옵션 추가, 고아객체 제거
private List<Child> childList = new ArrayList<>();
JpaMain
public class JpaMain {
public static void main(String[] args) {
EntityManagerFactory emf = Persistence.createEntityManagerFactory("hello");
EntityManager em = emf.createEntityManager();
EntityTransaction tx = em.getTransaction();
tx.begin();
try {
Child child1 = new Child();
Child child2 = new Child();
Parent parent = new Parent();
parent.addChild(child1);
parent.addChild(child2);
em.persist(parent);
// 추가한 부분
em.flush();
em.clear();
Parent findParent = em.find(Parent.class, parent.getId());
findParent.getChildList().remove(0); // 첫 번째 것 지움
tx.commit();
} catch (Exception e) {
tx.rollback();
e.printStackTrace(); // 하나 찍어봄
} finally {
em.close();
}
emf.close();
}
}
실행하면
14:24:42.779 [main] DEBUG org.hibernate.SQL -
Hibernate:
select
childlist0_.parent_id as parent_i3_2_0_,
childlist0_.id as id1_2_0_,
childlist0_.id as id1_2_1_,
childlist0_.name as name2_2_1_,
childlist0_.parent_id as parent_i3_2_1_
from
Child childlist0_
where
childlist0_.parent_id=?
14:24:42.780 [main] DEBUG org.hibernate.loader.plan.exec.process.internal.ResultSetProcessorImpl - Preparing collection initializer : [inflearn.exjpa.jpaExample.Parent.childList#1]
14:24:42.781 [main] DEBUG org.hibernate.loader.plan.exec.process.internal.CollectionReferenceInitializerImpl - Found row of collection: [inflearn.exjpa.jpaExample.Parent.childList#1]
14:24:42.781 [main] DEBUG org.hibernate.loader.plan.exec.process.internal.CollectionReferenceInitializerImpl - Found row of collection: [inflearn.exjpa.jpaExample.Parent.childList#1]
14:24:42.781 [main] DEBUG org.hibernate.engine.internal.TwoPhaseLoad - Resolving attributes for [inflearn.exjpa.jpaExample.Child#2]
14:24:42.781 [main] DEBUG org.hibernate.engine.internal.TwoPhaseLoad - Processing attribute `name` : value = null
14:24:42.781 [main] DEBUG org.hibernate.engine.internal.TwoPhaseLoad - Attribute (`name`) - enhanced for lazy-loading? - false
14:24:42.781 [main] DEBUG org.hibernate.engine.internal.TwoPhaseLoad - Processing attribute `parent` : value = 1
14:24:42.781 [main] DEBUG org.hibernate.engine.internal.TwoPhaseLoad - Attribute (`parent`) - enhanced for lazy-loading? - false
14:24:42.781 [main] DEBUG org.hibernate.engine.internal.TwoPhaseLoad - Done materializing entity [inflearn.exjpa.jpaExample.Child#2]
14:24:42.781 [main] DEBUG org.hibernate.engine.internal.TwoPhaseLoad - Resolving attributes for [inflearn.exjpa.jpaExample.Child#3]
14:24:42.781 [main] DEBUG org.hibernate.engine.internal.TwoPhaseLoad - Processing attribute `name` : value = null
14:24:42.781 [main] DEBUG org.hibernate.engine.internal.TwoPhaseLoad - Attribute (`name`) - enhanced for lazy-loading? - false
14:24:42.781 [main] DEBUG org.hibernate.engine.internal.TwoPhaseLoad - Processing attribute `parent` : value = 1
14:24:42.781 [main] DEBUG org.hibernate.engine.internal.TwoPhaseLoad - Attribute (`parent`) - enhanced for lazy-loading? - false
14:24:42.781 [main] DEBUG org.hibernate.engine.internal.TwoPhaseLoad - Done materializing entity [inflearn.exjpa.jpaExample.Child#3]
14:24:42.781 [main] DEBUG org.hibernate.engine.loading.internal.CollectionLoadContext - 1 collections were found in result set for role: inflearn.exjpa.jpaExample.Parent.childList
14:24:42.781 [main] DEBUG org.hibernate.engine.loading.internal.CollectionLoadContext - Collection fully initialized: [inflearn.exjpa.jpaExample.Parent.childList#1]
14:24:42.782 [main] DEBUG org.hibernate.engine.loading.internal.CollectionLoadContext - 1 collections initialized for role: inflearn.exjpa.jpaExample.Parent.childList
14:24:42.782 [main] DEBUG org.hibernate.loader.collection.plan.AbstractLoadPlanBasedCollectionInitializer - Done loading collection
14:24:42.782 [main] DEBUG org.hibernate.engine.transaction.internal.TransactionImpl - committing
14:24:42.782 [main] DEBUG org.hibernate.event.internal.AbstractFlushingEventListener - Processing flush-time cascades
14:24:42.783 [main] DEBUG org.hibernate.event.internal.AbstractFlushingEventListener - Dirty checking collections
14:24:42.783 [main] DEBUG org.hibernate.engine.spi.CollectionEntry - Collection dirty: [inflearn.exjpa.jpaExample.Parent.childList#1]
14:24:42.783 [main] DEBUG org.hibernate.engine.internal.Collections - Collection found: [inflearn.exjpa.jpaExample.Parent.childList#1], was: [inflearn.exjpa.jpaExample.Parent.childList#1] (initialized)
14:24:42.783 [main] DEBUG org.hibernate.event.internal.AbstractFlushingEventListener - Flushed: 0 insertions, 0 updates, 1 deletions to 3 objects
14:24:42.783 [main] DEBUG org.hibernate.event.internal.AbstractFlushingEventListener - Flushed: 0 (re)creations, 1 updates, 0 removals to 1 collections
14:24:42.783 [main] DEBUG org.hibernate.internal.util.EntityPrinter - Listing entities:
14:24:42.783 [main] DEBUG org.hibernate.internal.util.EntityPrinter - inflearn.exjpa.jpaExample.Child{parent=inflearn.exjpa.jpaExample.Parent#1, name=null, id=2}
14:24:42.783 [main] DEBUG org.hibernate.internal.util.EntityPrinter - inflearn.exjpa.jpaExample.Parent{name=null, childList=[inflearn.exjpa.jpaExample.Child#3], id=1}
14:24:42.783 [main] DEBUG org.hibernate.internal.util.EntityPrinter - inflearn.exjpa.jpaExample.Child{parent=inflearn.exjpa.jpaExample.Parent#1, name=null, id=3}
14:24:42.784 [main] DEBUG org.hibernate.SQL -
Hibernate:
/* delete inflearn.exjpa.jpaExample.Child */ delete
from
Child
where
id=?
DELETE 쿼리가 한 번 날아간 걸 볼 수가 있고,
H2 가서 확인하면
하나가 사라져 있음을 확인할 수 있음(ID : 2)
orphanRemoval 을 넣어두면
이 컬렉션에서 빠진 아이는 자동으로 삭제가 되는 옵션이다.
고아 객체 주의
마지막 내용 설명(CascadeType.REMOVE 처럼 동작)
Parent 수정
@OneToMany(mappedBy = "parent", orphanRemoval = true) // CASCADE옵션 제거함
private List<Child> childList = new ArrayList<>();
JPAMain 수정
public class JpaMain {
public static void main(String[] args) {
EntityManagerFactory emf = Persistence.createEntityManagerFactory("hello");
EntityManager em = emf.createEntityManager();
EntityTransaction tx = em.getTransaction();
tx.begin();
try {
Child child1 = new Child();
Child child2 = new Child();
Parent parent = new Parent();
parent.addChild(child1);
parent.addChild(child2);
em.persist(parent);
em.persist(child1);
em.persist(child2);
em.flush();
em.clear();
Parent findParent = em.find(Parent.class, parent.getId());
em.remove(findParent); // 조회한 parent를 아예 지워버림
tx.commit();
} catch (Exception e) {
tx.rollback();
e.printStackTrace(); // 하나 찍어봄
} finally {
em.close();
}
emf.close();
}
}
// => 그럼 orphanRemoval 입장에서는 이 컬렉션은 다 날아간 것임. 그래서 자식까지 다 delete 된다.
실행 결과
14:37:25.849 [main] DEBUG org.hibernate.SQL -
Hibernate:
/* delete inflearn.exjpa.jpaExample.Child */ delete
from
Child
where
id=?
Hibernate:
/* delete inflearn.exjpa.jpaExample.Child */ delete
from
Child
where
id=?
Hibernate:
/* delete inflearn.exjpa.jpaExample.Parent */ delete
from
Parent
where
id=?
쿼리 3번 나갔음을 확인할 수 있음.
영속성 전이 + 고아 객체, 그리고 생명 주기
3번 내용 예제
public class JpaMain {
public static void main(String[] args) {
EntityManagerFactory emf = Persistence.createEntityManagerFactory("hello");
EntityManager em = emf.createEntityManager();
EntityTransaction tx = em.getTransaction();
tx.begin();
try {
Child child1 = new Child();
Child child2 = new Child();
Parent parent = new Parent();
parent.addChild(child1);
parent.addChild(child2);
em.persist(parent);
em.flush();
em.clear();
Parent findParent = em.find(Parent.class, parent.getId());
findParent.getChildList().remove(0);
tx.commit();
} catch (Exception e) {
tx.rollback();
e.printStackTrace(); // 하나 찍어봄
} finally {
em.close();
}
emf.close();
}
}
Parent 수정
@OneToMany(mappedBy = "parent", cascade = CascadeType.ALL ,orphanRemoval = true)
private List<Child> childList = new ArrayList<>();
em.persist() 할 때도 parent만 했다.
그리고
em.remove() 할 때도 findParent만 했다.
자식을 persist 하지 않아도 자식이 저장된다.
자식을 remove 하지 않아도 자식이 지워진다.
중요한 것은 Parent는 JPA를 통해서 생명주기를 관리 중이다.
Child는 생명주기를 Parent가 관리하고 있다는 것.
728x90
'Spring > JPA 공부' 카테고리의 다른 글
기본 값 타입 (0) | 2023.08.26 |
---|---|
실전 예제 - 5. 연관관계 관리 (0) | 2023.08.25 |
영속성 전이(CASCADE) (0) | 2023.08.25 |
지연 로딩 활용 (0) | 2023.08.24 |
즉시 로딩 (0) | 2023.08.24 |
Comments