일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |
- 벌크연산
- jQueryUI
- JPA
- 프로젝트생성
- values()
- calendar
- fetchjoin
- 스프링데이터흐름
- fullcalendar
- 자바서블릿
- jQuery값전달
- LIST
- jscalendar
- paging
- 제너릭
- joinfetch
- springflow
- 엔티티직접사용
- jQuery값전송
- Generic
- JPQL
- namedQuery
- Hibernate
- javascriptcalendar
- 제네릭
- 대량쿼리
- 페치조인
- JQuery
- 페이징
- javaservlet
- Today
- Total
가자공부하러!
Hibernate(6) - 프록시, 즉시/지연 로딩, 연관관계 관리 본문
1. 프록시
> em.getReference() : DB조회를 미루는 가짜(프록시) 엔티티 객체 조회
- DB에 쿼리가 안나가는데 객체가 조회됨 -> 객체값이 실제 사용되는 시점에 DB에 쿼리를 날림
- class domain.Member$HibernateProxy$ojP0rbKz
> 사용 목적
- 엔티티와 연결된 모든 정보를 가져올 필요 없이 일부만 활용하고 싶을 때
- ex) Member를 조회할 때 Team은 조회하고 싶지 않다.
- 지연로딩
> 특징
- 프록시는 실제 클래스를 상속 받아서 만들어지므로 실제 클래스와 겉 모양이 같다.
- 이론상 사용하는 입장에서 진짜 객체인지 프록시 객체인지 구분할 필요가 없다.
- 프록시 객체는 최초 1회만 초기화되며, 실제 객체의 참조를(target) 보관
- 프록시 객체는 원본 엔티티를 상속받기 때문에 타입 체크 시 주의 필요
- ==비교 말고 instanceof 사용해야 함
- 영속성컨텍스트에 getReference()로 찾는 객체가 이미 있다면 실제 엔티티 리턴
- 실제 객체가 영속성 컨텍스트의 1차 캐시에 저장되어 있는 경우
- 그 반대도 성립 : 프록시객체가 영속성 컨텍스트에 있을 때 find 하면 프록시 객체 리턴
- 준영속상태일 때 프록시를 초기화하면 문제 발생
> 작동
- 순서 :
-> 프록시객체의 메소드 호출 -> 프록시객체가 영속성컨텍스트에게 초기화 요청
-> 영속성 컨텍스트가 DB조회 -> 실제 엔티티 생성
-> 프록시객체가 실제 엔티티(target)의 값을 가져다가 리턴
* 초기화 시점 : 프록시 객체가 실제 사용될 때(getter, setter 등)
> 응용
- 프록시 인스턴스의 초기화 여부 확인하는 메소드
- boolean emf.getPersistanceUnitUtil.isLoaded(Object Entity);
- 프록시 클래스 확인 메소드
- String entity.getClass().getName();
- 프록시 강제 초기화 메소드
- org.hibernate.Hibernate.initialize(Object Entity)
2. 즉시 로딩과 지연 로딩
> 지연 로딩
- @ManyToOne(fetch = FetchType.LAZY)를 연관 엔티티 변수 위에 선언
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "TEAM_ID")
private Team team;
- 이 때 Member에서 Team을 조회하게되면 프록시객체가 생성된다.
> 즉시 로딩
- @ManyToOne(fetch = FetchType.EAGER)를 연관 엔티티 변수 위에 선언
- 한 번에 연관 엔티티까지 모두 가져오는 쿼리가 실행됨
> 가능하면 지연 로딩만 사용하는게 좋다.
- JPQL로 지연 로딩으로 선언된 내용을 상황에 맞게 즉시 로딩처럼 사용할 수 있다.
- em.createQuery("select m from Member m join fetch m.team, Member.class);
- 즉시 로딩을 적용하면 전혀 예상하지 못한 SQL이 만들어진다.
- 즉시 로딩은 JPQL에서 N+1 문제를 일으킨다.(내가 날린 쿼리는 1개인데 쿼리 N개가 더 수행됨)
- Member만 가지고 온 상황에 FetchType.EAGER를 확인하고 또 다시 Team정보를 가져오게 된다.
- @ManyToOne, @OneToOne은 디폴트가 즉시 로딩이기 때문에 LAZY를 별도로 설정해 주어야 한다.
- @OneToMany, @ManyToMany는 디폴트가 지연로딩
3. 영속성 전이(CASCADE)
> 특정 엔티티를 영속 상태로 만들 때 연관된 엔티티도 함께 영속 상태로 만들고 싶을 때
> 연관관계를 매핑하는 것과는 전혀 관련 없음
> @OneToMany(mappedBy = "parent", cascade = CascadeType.ALL)
- ALL, PERSIST, REMOVE, MERGE, REFRESH, DETACH
> 주의 : 하위 엔티티가 다른 엔티티들과 연관관계가 있는 경우에는 사용하지 말것
4. 고아 객체
> 부모 엔티티와 연관관계가 끊어진 자식 엔티티
> @OneToMany(orphanRemoval = true)
@OneToMany(mappedBy = "parent", orphanRemoval = true)
private List<Child> children = new ArrayList<Child>();
> 위처럼 설정했을 때, children 리스트에서 특정 Child 객체를 remove하면 delete쿼리를 수행한다.
> 주의 : 충돌을 예방하기 위해서는 참조하는 곳이 하나일 때만 사용해야 함
> 주의 : 부모를 삭제하면 자식이 고아가되므로 orphanRemoval옵션일 때에는 자식도 삭제된다.
5. 영속성 전이 + 고아 객체
> 도메인 주도 설계(DDD)의 Aggregate Root 개념을 구현할 때 유용
> @OneToMany(mappedBy = "parent", cascade = CascadeType.ALL, orphanRemoval = true)
> 부모 엔티티를 통해서 자식의 생명주기를 관리할 수 있다.
'공부 > Java' 카테고리의 다른 글
Hibernate(8) - 객체지향 쿼리 언어(JPQL, QueryDSL 등) (0) | 2019.11.25 |
---|---|
Hibernate(7) - 값 타입 (0) | 2019.11.22 |
Hibernate(5) - 연관관계 매핑 (0) | 2019.11.20 |
Hibernate(4) - 엔티티 매핑 (0) | 2019.11.20 |
Hibernate(3) - JPA 영속성 컨텍스트, 플러시, 준영속 상태 (0) | 2019.11.20 |