Notice
Recent Posts
Recent Comments
Link
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
Tags
- MySQL
- undirected graphical model
- 스터디
- 선형판별분석
- SCPC
- secant
- 1차예선
- 5397번
- CH01
- chapter01
- chapter02
- falsePosition
- Perceptron Convergence theorem
- 근구하기
- graphical models
- 개발순서
- directed graphical model
- 알고리즘대회
- 2018
- 인공지능
- 선형분류
- Fisher discriminant analysis
- vector미분
- 델타 rule
- 로지스틱 회귀
- Numerical optimization
- bisection
- 이것이 MySQL이다
- 알고리즘
- 자바ORM표준JPA프로그래밍
Archives
- Today
- Total
computer_study
[JPA] 08. 프록시와 연관관계 관리 본문
1. 프록시
지연로딩 : 엔티티를 조회할 때 엔티티를 항상 사용하진 않기에, 엔티티가 실제 사용될 때 까지 데이터베이스 조회를 지연하는 방법
이런 지연 로딩을 위해 조회를 지연할 수 있는 가짜 객체가 필요. 이것이 프록시.
1.1 프록시 기초
- 프록시의 특징
- 프록시 클래스는 실제 클래스를 상속받아 만들어진다.
- 사용자 입장은 프록시 객체와 진짜 객체를 구분하지않고 사용할 수 있다.
- 처음 사용할 떄 한 번만 초기화 된다. (실제 엔티티로 바뀌는 것이 아니라 프록시를 통해 접근할 수 있게 되는 것)
- 원본 엔티티를 상속받기에 타입 체크 시에 주의해서 사용해야 한다.
- 영속성 컨텍스트에 찾는 엔티티가 이미 있으면 DB접근이 필요 없기에 실제 엔티티를 반환한다.
- 준영속 상테의 프록시를 초기화하면 문제가 발생한다.
- 프록시 객체의 초기화
- 프록시객체가 실제 사용되어 실제 엔티티 객체를 생성하는 것이 프록시 객체의 초기화
1.2 프록시와 식별자
- 엔티티를 프록시로 조회 시 PK값을 파라미터로 전달. 프록시 객체는 이 식별자 값을 보관한다.
- 결국 식별자를 조회 시에는 DB접근을 안하기에 프록시를 초기화 하지 않는다.(엔티티 접근 방식을 프로퍼티로 설정한 경우)
- 엔티티 접근 방식이 필드면 프록시 객체를 초기화한다.
- 연관관계 설정 시 프록시를 사용하면 DB 접근 횟수를 줄일 수 있기에 이익을 볼 수 있다.
1.3 프록시 확인
- PersistenceUnitUtil.isLoaded(Object entity)메소드를 통해 프록시 인스턴스의 초기화 여부를 확인할 수 있다.
- 초기화가 되어있거나 프록시 인스턴스가 아니면 true를 반환
- 조회한 엔티티가 진짜인지, 프록시로 조회인지 확인을 위해선 클래스 명을 출력해보면 알 수 있다.
2. 즉시 로딩과 지연 로딩
2.1 즉시 로딩
- 엔티티를 조회할 때 연관된 엔티티도 함께 조회한다.
- @ManyToOne(fetch = FetchType.EAGER)로 설정
- ex) member를 호출했다면 그에 연관된 team도 함께 조회
- 조회 시 쿼리를 두 번 수행하지 않고, 가능하면 조인 쿼리를 사용(즉시 로딩을 최적화하기 위해)
- 비즈니스 로직에서 항상 같이 조회하는 경우에 즉시로딩을 쓰면 좋다.
2.2 지연 로딩
- 연관된 엔티티를 실제 사용할 때 조회한다.
- @ManyToOne(fetch=FetchType.LAZY)로 설정
- ex) member호출 시 연관된 team은 조회하지 않고 team멤버변수에 프록시 객체를 넣어둔다.
- 실제 사용이 될 떄 프록시 객체가 데이터 로딩을 수행(초기화)
- 필요할 떄 마다 실행할 때가 효율적이 때도 있다.
3. 지연 로딩 활용
예사 상황
- 회원은 팀 하나에만 소속 (N:1) / 회원, 팀이 자주 함께 사용 (즉시로딩)
- 회원은 여러 주문내역을 가진다 (1:N) / 회원, 주문 내역은 가끔 함께 사용 (지연로딩)
- 주문내역은 상품정보를 가진다 (N:1) / 자주 함께 사용 (즉시로딩)
@Entity
public class Member{
@Id
private String id;
private String username;
private Integer age;
@ManyToOne(fetch=FetchType.EAGER)
private Team team;
@OneToMany(mappedBy="member", fetch=FetchType.LAZY)
private List<Order> orders;
//getter, setter...
}
3.1 프록시와 컬렉션 래퍼
- 하이버네이트가 엔티티를 영속 상태로 만들 때
- 엔티티에 컬렉션이 있다면 원본 컬렉션을 하이버네이트가 제공하는 내장 컬렉션으로 변경하는 것이 컬렉션 래퍼
- (컬렉션을 추적하고 관리 할 목적)
- 컬렉션 래퍼도 컬렉션에 대한 프록시 역할을 한다.
3.2 JPA 기본 fetch 전략
- 연관된 엔티티가 하나라면 즉시 로딩
- 컬렉션이면 지연 로딩(컬렉션을 로딩하는 것에는 비용이 많이 들고, 많은 데이터가 로딩될 수 있기에)
- 항상 지연 로딩을 기본으로 하고 필요할 때만 즉시 로딩을 한다고 생각하면 된다.
- 컬렉션을 즉시로딩 한다면 항상 OUTER JOIN이 사용된다. (ex. 회원이 한 명도 없는 팀을 내부조인하면 팀까지 조회가 안되는 문제가 발생하기에)
4. 영속성 전이: CASCADE
- 특정 엔티티를 영속 상태로 만들 때, 연관된 엔티티도 함께 영속 상태로 만들고 싶다면 영속성 전이 기능을 사용
- 이때 CASCADE를 사용
- +) JPA에서 엔티티를 저장할 때 연관된 모든 엔티티는 영속 상태여야 한다.
- 연관관계 매핑과는 관련이 없다. (연관된 엔티티도 같이 영속화하는 편리함을 제공할 뿐)
4.1 저장
@Entity
public class Parent{
@OneToMany(mappedBy="parent", cascade=CascadeType.PERSIST) // 옵션 설정
private List<Child> children = new ArrayList<Child>();
...
}
/////////////////
private static void example(EntityManager em){
Child child1 = new Child();
Child child2 = new Child();
Parent parent = new Parent();
child1.setParent(parent); // 연관관계 추가
child2.setParent(parent);
parent.getChildren().add(child1);
parent.getChildren().add(child2);
// 부모, 연관된 자식들 저장
em.persist(parent)
}
4.2 삭제
기존이라면 각각의 엔티티를 하나씩 제거애햐 하지만 CascadeType.REMOVE로 설정이 되어있다면 연관된 엔티티도 함께 삭제가 된다
// 기존
Parent findParent = em.find(Parent.class, 1L);
Child findChild1 = em.find(Child.class, 1L);
Child findChild2 = em.find(Child.class, 2L);
em.remove(findChild1);
em.remove(findChild2);
em.remove(findParent);
// CascadeType.REMOVE사용 시
Parent findParent = em.find(Parent.class, 1L);
em.remove(findParent);
4.3 CASCADE의 종류
public enum CascadeType{
ALL,
PERSIST,
MERGE,
REMOVE,
REFRESH,
DETACH
}
// PERSIST, REMOVE는 바로 전이가 발생되지 않고 플러시를 호출할 때 전이가 발생
5. 고아 객체
- JPA는 부모 엔티티와 연관관계가 끊어진 자식 엔티티를 자동으로 삭제할 수 있게 한다. (고아객체(ORPHAN) 제거)
- 자식엔티티의 참조만 제거하면 자동으로 삭제되도록 할 수 있다.
@Entity
public class Parent {
@Id @GeneratedValue
private Long id;
@OneToMany(mappedBy = "parent", orphanRemoval = true)
private List<Child> children = new ArrayList<Child>();
...
}
/////////////
Parent parent1 = em.find(Parent.class. id);
parent1.getChildren().remove(0); // 자식 엔티티를 컬렉션에서 제거
////////// 모든 자식 엔티티를 제거하는 방법
parent1.getChildren().clear();
- 참조하는 곳이 하나일 때만 사용해야 한다.(특정 엔티티가 개인 소유하는 엔티티에만 이 기능을 적용해야 한다.)
- @OneToOne, @OneToMany에서만 사용할 수 있다.
- 부모를 제거하면 자식은 고아가 되고, 자식 또한 제거되기에 CascadeType.REMOVE를 설정한 것과 같이 동작한다.
6. 영속성 전이 + 고아 객체, 생명 주기
- CascadeType.ALL + orpahnRemoval = ture 동시 사용 시
- 부모 엔티티를 통해서 자식의 생명 주기를 관리할 수 있다.
- 자식을 저장하려면 부모에 등록만 하면 되고, 자식을 삭제하려면 부모에서 제거만 하면 된다.
'스터디 > 자바 ORM표준 JPA 프로그래밍' 카테고리의 다른 글
[JPA] 12. 스프링 데이터 JPA (0) | 2022.09.26 |
---|---|
[JPA]10. 객체지향 쿼리 언어 (0) | 2022.09.05 |
[JPA] 07. 고급 매핑 (0) | 2022.08.08 |
[JPA] 06. 다양한 연관관계 매핑 (0) | 2022.07.31 |
[JPA] 05. 연관관계 매핑 기초 (0) | 2022.07.25 |
Comments