1. 프록시 패턴
- 프록시 패턴이란 실제 객체 대신 가상의 객체(Proxy Object)를 사용하는 디자인 패턴이다.
이를 이용하여 실제 객체에 대한 접근 제어 용도로 사용할 수 있다.
프록시 객체에는 실제 객체의 레퍼런스를 가지고 있다. 또한 프록시와 객체 클래스 모두 똑같은 인터페이스를 구현하고 있기 때문에 실제 객체와 동등하게 사용할 수 있다. 클라이언트는 객체를 직접 접근하는 것이 아니라 프록시를 중간에 두고 실제 객체와 데이터를 주고 받는다.
2. JPA에서의 프록시
회원과 팀의 엔터티 관계를 생각할때
비즈니스 로직에 따라 회원을 조회할 때 그와 연관된 팀 엔터티가 항상 필요한 것은 아니다.
JPA 에서는 이런 문제를 해결하기 위해 지연로딩을 이용하여 해결한다.
(지연 로딩이란 값을 실제 사용하는 시점에 데이터베이스에서 조회하는 것이다.)
이러한 지연 로딩을 위해 실제 엔터티가 아닌 가짜 객체가 필요한데 그것이 바로 프록시 객체다.
보통 JPA에서 엔터티를 조회하기 위해서는 다음과 같이 사용한다.
이렇게 엔터티를 조회하게 되면 사용 여부와 상관없이 데이터베이스에서 전체 엔터티를 조회하게 된다.
실제 사용시점까지 데이터베이스를 조회 하기 위해서는 getReference 메소드를 사용하면 된다.
그러면 프록시 객체가 리턴되게 된다.
이 메소드를 호출할경우 엔터티를 조회하지 않고 후에 데이터베이스를 접근할 수 있는 프록시 객체를 반환한다.
클래스 비교
프록시 객체는 다음과 같이 동작한다.
1) 프록시 객체의 getName()가 호출되면 실제 객체를 조회를 시도한다.
2) 실제 객체가 생성되어있지 않다면 영속성 컨텍스트에서 실제 객체 생성을 요청한다.(이를 프록시 초기화라고 부른다.)
3) 영속성 컨텍스트에서 데이터베이스를 조회해서 실제 엔터티를 생성한다.
4) 프록시 객체에 실제 엔터티의 참조 값을 target 멤버변수에 저장한다.
5) 실제 객체의 getName()을 호출하여 결과를 리턴한다.
프록시 객체 특징
1) 프록시 초기화는 처음 사용될때 한번만 초기화된다.
2) 초기화 된다고 해서 프록시객체가 실제 객체로 바뀌는 것이 아니라 참조값이 target변수에 들어가는 것이다.
3) 실제 객체가 영속성 컨텍스트에 이미 있다면 em.getReference를 호출해도 프록시가 아닌 실제 객체가 리턴된다.
4) 엔터티를 프록시로 조회할때 프록시 내부의 식별자 변수(PK)를 이용하는데 getId()를 사용해서 PK를 조회하려고 해도 프록시가 초기화 되지 않는다.
3. 지연로딩과 즉시 로딩
- 즉시 로딩 : 엔터티를 조회할때 연관된 엔터티도 함께 조회됨(FetchType.EAGER)
- 지연 로딩 : 엔터티를 조회할때 연관된 엔터티가 실제 사용될 때 조회됨(FetchType.LAZY)
쿼리에서도 차이가 난다.
엔터티가 서로 같이 쓰이면 즉시 로딩을 사용하는 것이좋고,
가끔 사용되는 경우엔는 지연 로딩을 사용하는 것이 좋다.
JPA에서 FetchType 기본전략으로
ManyToOne OneToOne에서는 즉시 로딩을 사용한다.
또 OneToMany ManyToMany에서는 지연 로딩을 사용한다.
생각 해보면 XToOne에서는 연관된 것 하나만 불러와도 되니 비용이 적기 때문에 그랬을 것이다.
반면 XToMany에서는 컬렉션을 로디잏야 되기 떄문에 많은 데이터를 불러와야 하기 때문일 것이다.
4. 영속성 전이
JPA에서는 Cascade 옵션을 이용해서 영속성 전이 기능을 제공한다.
Parent -> Child 관계에서 영속성 전이가 없다면
child1.setParent(parent1);
child2.setParent(parent1);
parent.getChilds().add(child1);
parent.getChilds().add(child2);
em.persist(parent1) //부모 1 영속성 저장
em.persist(child1) //자식1 영속성 저장
em.persist(child2) //자식 2 영속성 저장
이런식으로 각각 영속성 저장 해야할 것이다.
JPA의 Cascade을 사용하면 부모 하나만 저장해도 연관된 자식이 모두 영속성 컨텍스트에 저장된다.
@OneToMany(mappedBy = "parent", cascade = CascadeType.PERSIST)
List <Child> childs;
//
연관관계 저장
//
em.persist(parent1)
Cascade 종류는 다음과 같다.
CascadeType.ALL //모두
CascadeType.PERSIST //영속
CascadeType.MERGE // 병합
CascadeType.REMOVE // 삭제
CascadeType.REFRRESH //update
CascadeType.DETACH //준영속
//여러 속성을 배열로 사용할수도있음
{CascadeType.PERSIST, CascadeType.REMOVE}
CascadeType. Refresh => Sync to database
merge => detach상태에서 연관 엔터티를 추가하거나 변경된 이후에 부모 엔터티가 merge 를 하면 그 변경사항이 적용됨
'JAVA' 카테고리의 다른 글
Java 멀티쓰레드 동기화 - (2) Synchronized (0) | 2020.10.11 |
---|---|
Java 멀티쓰레드 동기화 - (1) Volatile (0) | 2020.10.03 |
Spring Data JPA (0) | 2020.08.30 |
JDBC, MyBatis (0) | 2020.08.27 |
JAVA 8 - 람다 추가 (0) | 2020.08.15 |