반응형
이 포스팅에서 작성하는 내용은 자바 ORM 표준 JPA 프로그래밍 (김영한 지음) 에서 발췌하였습니다.
1. 프록시
DB 조회를 미루는 가짜 엔티티. (실제로 객체가 사용될 때. 그 때 조회함)
1) 프록시 기초
- em.find() vs em.getReference()
- em.find() : DB를 통해서 실제 엔티티 객체 조회
- em.getReference() : DB 조회를 미루는 가짜(프록시) 엔티티 (실제로 객체가 사용될 때. 그 때 조회함)
2) 프록시 특징
- 실제 클래스를 상속 받아서 만들어짐
- 실제 클래스와 겉 모양이 같다.
- 사용하는 입장에서는 진짜 객체인지 프록시 객체인지 구분하지않고 사용하면 됨
- 프록시 객체는 실제 객체의 참조를 보관
- 프록시 객체를 호출하면 프록시 객체는 실제 객체의 메소드 호출
- 프록시 객체는 처음 사용할 때 한 번만 초기화
- 프록시 객체는 원본 엔티티를 상속받음. 따라서 타입 체크 시 주의(==이 아닌, instance of 사용)
- 영속성 컨텍스트에 찾는 엔티티가 이미 존재하면 em.getReference()를 호출해도 실제 엔티티를 반환
- 영속성 컨텍스트의 도움을 받을 수 없는 준영속 상태일 때, 프록시를 초기화하면 문제 발생
3) 프록시 객체의 초기화
프록시 객체를 초기화 시, 프록시 객체가 실제 엔티티로 바뀌는 것이 아니라 초기화되면 프록시 객체를 통해서 실제 엔티티에 접근하는 방식
- 객체가 실제로 사용됨 ex)member.getName()
- 실제 객체의 참조를 보관하던 프록시 객체가 영속성 컨텍스트에 데이터를 요청
- 영속성 컨텍스트에서 DB로 값을 조회함
- 실제로 해당 객체를 생성한 뒤 DB에서 얻은 값을 넣음
4) 프록시 확인
- 프록시 인스턴스의 초기화 여부 확인
- PersistenceUnitUtil.isLoaded(Object entity)
- 초기화 X : false
- 초기화 O : true
- 프록시 클래스 확인
- entity.getClass().getName() 출력 (..javasist.. or HibernateProxy...)
- 프록시 강제 초기화
- org.hibernate.Hibernate.initialize(entity);
- JPA 표준에는 강제 초기화가 없다.
2. 즉시로딩과 지연로딩
즉시로딩 : 관련된 엔티티를 한 번에 같이 조회
지연로딩 : 관련된 엔티티는 나중에 조회(실제로 사용될 때 조회)
1) 프록시와 즉시로딩 주의
- 가급적 지연 로딩만 사용(특히 실무에서)
- 즉시 로딩을 적용하면 예상하지 못한 SQL이 발생
- 즉시 로딩은 JPQL에서 N+1 문제를 일으킨다. (즉시 로딩 해야하는 관련 엔티티를 조회하기 위해 추가 쿼리가 나감)
- @ManyToOne, @OneToOne의 Default : 즉시 로딩. → 지연 로딩으로 설정
- @OneToMany, @ManyToMany의 Default : 지연 로딩
2) 지연 로딩 활용 - 실무
- 모든 연관관계에 지연 로딩을 사용
- 실무에서 즉시 로딩 사용 X
- JPQL fetch 조인이나 엔티티 그래프 기능 사용
- 즉시 로딩은 복잡하고 상상하지 못한 쿼리 발생
3. 영속성 전이(CASCADE)와 고아 객체
1) 영속성 전이(CASCADE)
- 특정 엔티티를 영속 상태로 만들 떄 연관된 엔티티도 함께 영속 상태로 만들고 싶을 때 사용
- ex) 부모 엔티티를 저장할 때 자식 엔티티도 함께 저장
2) 주의사항
- 영속성 전이는 연관관계를 매핑하는 것과 아무 관련이 없음
- 엔티티를 영속화할 때 연관된 엔티티도 함께 영속화하는 편리함을 제공하기만 함
3) 종류
- ALL : 모두 적용
- PERSIST : 영속
- REMOVE : 삭제
- MERGE : 병합
- REFRESH : REFRESH
- DETACH : DETACH
4. 고아 객체
1) 고아 객체
고아 객체 : 부모 엔티티와 연관관계가 끊어진 자식 엔티티
- 고아 객체 제거 : 부모 엔티티와 연관관계가 끊어진 자식 엔티티를 자동으로 삭제
- orphanRemoval = true
Parent p1 = em.find(Parent.class, id);
p1.getChild().remove(0); // 자식 엔티티를 컬렉션에서 제거
↓ 쿼리
DELETE FROM CHILD WHERE ID = ?;
2) 주의
- 참조가 제거된 엔티티는 다른 곳에서 참조하지 않는 고아 객체로 판단하고 삭제하는 기능임
- 참조하는 곳이 하나일 때 사용해야함
- 특정 엔티티가 개인 소유할 떄 사용
- @OneToOne, @OneToMany일 경우에만 가능
- 참고) 부모를 제거하면 자식은 고아가 됨 → 부모를 제거하면 자식도 함께 제거된다는 뜻
3) 영속성 전이 + 고아 객체, 생명주기
- CascadeType.ALL + orphanRemoval=true
- 스스로 생명주기를 관리하는 엔티티는 em.persist()로 영속화하고 em.remove()로 제거
- 두 옵션을 모두 활성화하면 부모 엔티티에서 자식의 생명주기 관리 가능
- 도메인 주도 설계(DDD)의 Aggregate Root 개념을 구현할 때 유용
반응형
'BE > JPA' 카테고리의 다른 글
[JPA] 15. 다양한 쿼리를 이용한 조회 (0) | 2022.04.26 |
---|---|
[JPA] 14. 값 타입 (0) | 2022.04.25 |
[JPA] 12. 상속관계 매핑 (0) | 2022.04.19 |
[JPA] 11. 다양한 연관관계 매핑 (0) | 2022.04.18 |
[JPA] 호환되는 버전 찾기 (0) | 2022.04.18 |