목차
em.getReference() 메서드
@Entity
public class Member{
@Id @GeneratedValue
@Column(name="member_id")
private Long id;
private String name;
@ManyToOne
@JoinColumn(name="team_id")
private Team team;
private static void printMember(Member member){
System.out.println("member : " + member);
}
private static void printMemberAndTeam(Member member){
System.out.println("member : " + member);
System.out.println("team : " + member.getTeam());
}
}
@Entity
public class Team{
@Id @GeneratedValue
@Column(name="team_id")
private Long id;
private String name;
}
Member를 DB에서 찾아와서 출력한다고 하자.
Team의 내용을 출력한다면 printMemberAndTeam()을 사용해야한다.
Team의 내용을 출력하지 않는다면 printMember()를 사용해야한다.
printMember를 사용할 때 JPA에서 Team의 내용을 가져오는데 사용하지 않는다면 자원의 낭비 아닐까?
이럴 때 사용하는게 프록시이다.
JPA는 DB에서 실제 엔티티를 조회하는 em.find()메서드와
조회를 최대한 미루기 위해 사용하는 가짜(프록시) 엔티티를 조회하는 em.getReference()메서드를 제공한다.
em.getReference는 DB에 쿼리가 안나가는데 조회가 되는 것이다.
Member member = new Member();
member.setName("hello");
em.persist(member);
em.flush();
//insert문 전송
em.clear();
Member findMember = em.getReference(Member.class, member.getId());
System.out.println("findMember : " + findMember.getClass());
//findMember : class hellojpa.Member$HibernateProxy$nMvq2opM
System.out.println("findMember.name : " + findMember.getName());
//select문 전송
//findMember.name : hello
getReference를 사용하고 클래스를 조회해보면 $HibernateProxy$~~ 라는 클래스가 조회된다.
프록시란?
- 실제 클래스를 상속받아서 만들어진다.
- 실제 객체의 참조(target)을 보관한다.
- 프록시 객체를 호출하면, 프록시는 실제 객체의 메소드를 호출한다.
- 프록시 객체는 처음 사용할 때 한번만 초기화된다.
- 초기화는 영속성 컨텍스트를 통해 DB에서 조회 후 실제 엔티티를 생성하여 프록시에게 연결하는 작업이다.
- ==비교 대신 instance of 를 사용해야한다.
- 프록시가 초기화된다 해도 실제 엔티티로 바뀌는 것은 아니다. 프록시를 통해 엔티티에 접근하는 것이다.
- 영속성 컨텍스트에 찾는 엔티티가 있다면 em.getReference()를 호출해도 실제 엔티티 반환한다.
- 영속성 컨텍스트의 도움을 받을 수 없는 준영속 상태일 때, 프록시를 초기화하면 LazyInitializationException 예외를 발생시킨다.
즉시 로딩 : FetchType.EAGER
printMemberAndTeam()처럼 Member와 Team이 연결되어있을때
항상 Member와 Team을 조인해서 조회하는 방법이다.
주의!!
- 가급적 지연 로딩만 사용하자.
- 즉시 로딩을 적용하면 연관관계의 모든 테이블을 조인해서 가져오기때문에
Member만 출력한다해도 JPA에서는 모든 테이블을 조회한다
- 즉시로딩은 JPQL에서 N+1문제를 일으킨다.
select m from Member m 했을 때, Member를 가져왔더니 Team이 연결되어있다
앗! Team도 조회해야해! 하고 Team을 조회하는 쿼리를 전송하게된다. (Select문이 2번 호출됨)
지연 로딩 : FetchType.LAZY
printMember()처럼 Member와 Team이 연결되어있지만
Member에 대한 것만 먼저 조회하고, Team은 필요할 때가 되어서야 조회하는 방법이다.
영속성 전이 CASCADE
특정 엔티티를 영속상태로 만들 때, 연관된 엔티티도 함께 영속상태로 만드는 것
부모 엔티티를 저장할 때, 자식 엔티티도 함께 저장하고 싶을 때 사용한다.
cascade = CascadeType.PERSIST
게시판 - 첨부파일 관계처럼 "게시판"에서만 "첨부파일"을 관리할 때 사용하면 유용하다.
첨부파일을 다른 엔티티에서도 관여하게된다면, 사용하지 말자
고아객체
부모 엔티티와 연관관계가 끊어진 자식 엔티티를 자동으로 삭제한다.
orphanRemoval = true
parent.getChildList().remove(0) 하는 경우
삭제된 child에 대해 Delete쿼리가 전송된다.
'Backend' 카테고리의 다른 글
[Spring Security] OAuth 카카오 로그인하기 (0) | 2022.02.23 |
---|---|
[JPA] 값 타입(기본값, @Embedded, 값타입 컬렉션) (0) | 2022.02.22 |
[JPA] 상속관계 매핑, 공통 속성 매핑 (0) | 2022.02.21 |
[JPA] 다양한 연관관계 매핑(다대일, 일대일, 다대다) (0) | 2022.02.21 |
[JPA]영속성 관리 : 내부 동작 방식 (0) | 2022.02.21 |