-
자바 ORM 표준 JPA 프로그래밍 - 기본편 섹션08BACKEND/Spring 2022. 11. 14. 21:59
프록시
프록시는 왜 사용해야할까?
멤버를 조회할 때 team도 함께 조회를 해야할까? 라는 질문을 던져보자. 이건 비지니스 로직에 따라 달라진다.
만약 비지니스 로직에서 멤버와 팀을 같이 출력한다면, 멤버의 팀 정보를 불러온 다음에 연관된 팀도 가져오게 된다.
만일 멤버만 출력한다면, member.get만 챙겨오면 된다. 이럴 때 연관관계가 있다고 팀까지 가져오면 손해이다.
이런 경우에는 어떻게 해야할까? 이것을 해결하려면 프록시를 정확하게 이해해야 한다.
프록시 기초
• em.find() vs em.getReference()
• em.find(): 데이터베이스를 통해서 실제엔티티 객체 조회
• em.getReference():데이터베이스 조회를 미루는 가짜(프록시) 엔티티 객체 조회
프록시 특징
• 실제클래스를 상속받아서 만들어진다.
• 실제클래스와 겉모양이 같다.
• (이론상으로) 사용하는 입장에서는 진짜 객체인지 프록시 객체인지 구분하지 않고 사용하면 된다.
• 프록시 객체는 실제 객체의 참조(target)를 보관
• 프록시 객체를 호출하면 프록시 객체는 실제 객체의 메소드 호출
프록시 객체 초기화
Member member = em.getReference(Member.class, “id1”); member.getName();
이와 관련해서는 더 공부를 해볼 예정이다.
즉시 로딩과 지연 로딩
처음에 나왔던 질문인, member를 조회할 때, Team도 함께 조회해야할까?
비지니스 로직이 멤버만 조회하는 경우가 많다면,
지연로딩 LAZY을 사용해서 프록시로 조회
@Entity public class Member { @Id @GeneratedValue private Long id; @Column(name = "USERNAME") private String name; @ManyToOne(fetch = FetchType.LAZY) //** @JoinColumn(name = "TEAM_ID") private Team team; }
만약 member와 Team을 자주 함께 사용한다면?
즉시로딩 EAGER를 사용해서 함께 조회
@Entity public class Member { @Id @GeneratedValue private Long id; @Column(name = "USERNAME") private String name; @ManyToOne(fetch = FetchType.EAGER) //** @JoinColumn(name = "TEAM_ID") private Team team; }
프록시와 즉시로딩 주의
• 가급적 지연로딩만 사용하기
• 즉시로딩을 적용하면 예상하지 못한 SQL이 발생할 수 있다.
• 즉시로딩은 JPQL에서 N+1 문제를 일으킨다.
• @ManyToOne, @OneToOne은 기본이 즉시로딩이므로 LAZY로 지연로딩으로 변환해 주어야 한다.
• @OneToMany, @ManyToMany는 기본이 지연로딩이다.
영속성전이 + 고아객체, 생명주기
• CascadeType.ALL + orphanRemovel=true
• 스스로 생명주기를 관리하는 엔티티는 em.persist()로 영속화, em.remove()로 제거
• 두 옵션을 모두 활성화하면 부모 엔티티를 통해서 자식의 생명주기를 관리할 수 있음
• 도메인 주도 설계(DDD)의 Aggregate Root 개념을 구현할 때 유용
'BACKEND > Spring' 카테고리의 다른 글
[Spring Boot/JPA] JPA 의존성 추가, 도메인 개발 (0) 2023.02.15 [Spring / Spring Boot] 단위 테스트 코드 작성해보기 (0) 2023.02.13 실전! 스프링 부트와 JPA 활용1 - 웹 애플리케이션 개발 : 섹션 2(작성 중) (0) 2022.11.13 실전! 스프링 부트와 JPA 활용1 - 웹 애플리케이션 개발 섹션 1(작성 중) (0) 2022.11.13 [Spring - JPA ORM 표준 JPA 프로그래밍 ] JPA 시작 (2) 2022.10.03