프록시와 연관관계 관리
📒 em.find() vs em.getReference()
em.find() → DB를 통해서 실제 엔티티 객체 조회
em.getReference() → DB조회를 미루는 가짜(프록시) 엔티티 객체 조회
프록시란?
- 실제 클래스를 상속 받아서 만들어짐
- 실제 클래스와 겉 모양이 같음
- 개발자 입장에서는 진짜 객체인지 프록시 객체인지 구분X
- 프록시 객체는 실제 객체의 참조(target)을 보관
- 프록시 객체를 초기화하면 프록시 객체는 실제 객체의 메소드 호출
- 프록시 객체는 JPA성능 최적화를 위해 제공하는 기술 → 지연로딩 핵심 원리
📒 프록시 초기화란?
프록시가 실제 엔티티 객체를 불러오는 과정
Member refMember=em.getReference(Member.class,member1.getId());
refMember.getUsername(); //프록시 객체 초기화
프록시 특징
- 프록시 객체는 처음 사용할 때 한 번만 초기화
- 프록시 객체를 초기화 할 때, 프록시 객체가 실제 엔티티로 변하는 것이 아니라 프록시 객체를 통해 엔티티 객체에 접근이 가능
- 영속성 컨텍스트에 찾는 엔티티가 있으면 em.getReference()를 호출해도 실제 엔티티 반환
- 준영속 상태일 때, 프록시를 초기화하면 문제 발생 → 초기화 요청을 하면 영속성 컨텍스트에서 엔티티 객체를 조회하기 때문
- 프록시 객체는 식별을 위해 id(정확히는 @Id 로 지정한 식별자) 값만 가지고 있을 뿐 실제 엔티티 객체의 속성 값들을 가지고 있지 않음
- em.getReference()를 호출하면, 해당 엔티티의 실제 인스턴스가 아닌 프록시 객체가 생성되어 영속성 컨텍스트에 반환
📒 em.flush() 와 em.clear()를 하는 이유
→ 조회 쿼리를 보기 위해 persist()를 하고 바로 find()를 하면 영속성 컨텍스트에 있는 데이터를 가져오기 때문에 조회쿼리를 볼 수 없다.
em.flush(), em.clear()를 하면 DB에 데이터를 반영하고, 영속성 컨텍스트를 지우기 때문에 find()를 하면 DB에서 데이터를 조회하기 때문에 쿼리를 볼 수 있다.
* 트랜잭션을 커밋할 때 자동으로 플러시가 발생
프록시가 생성되면 영속성 컨텍스트는 프록시를 반환한다
영속성 컨텍스트의 특징으로 동일성 보장이 있다.
한 번 프록시로 만들어진 객체는 프록시 초기화를 하더라도 실제 엔티티로 변환되지 않고 참조값만 가지는데 이 때문에 동일성을 보장해주기 위해서 한 트랜잭션 내에서 최초 생성이 프록시로 된 엔티티는 이후 초기화 여부에 상관 없이 영속성 컨텍스트가 무조건 같은 프록시 객체를 반환
반대로
반대의 경우 동일한 트랜잭션안에서 처음에 em.find()를 사용하면 실제 엔티티가 반환되고, em.getReference()를 사용해도 동일성 보장을 위해 실제 엔티티를 반환
지연로딩 vs 즉시 로딩
지연 로딩(LAZY)
연관관계가 되어있는 관계에서 필요할 때 쿼리문을 날리는 것을 의미
Member member=em.find(Member.class,member.getId());
- 위의 코드가 실행될 때 지연로딩일 경우, Member쿼리는 나가지만 Team엔티티의 값을 호출하지 않았기 때문에 프록시 객체가 생성되고 쿼리는 나가지 않음
Member member=em.find(Member.class,member.getId());
Team team=member.getTeam().getName(); //프록시 초기화
위의 코드처럼 Team객체의 값을 이용하려고 하는 경우에 프록시 객체가 초기화 되고, 쿼리가 나감
즉시 로딩(EAGER)
연관관계가 되어있는 관계들을 목적과 상관없이 모두 쿼리문을 날리는 것
위의 사진처럼 Member와 Team이 서로 연관관계인 경우
Member member=em.find(Member.class,member.getId());
이렇게 호출을 하게되면 즉시 로딩은 Team엔티티에 대한 쿼리도 개발자의 의지와 상관없이 쿼리문을 날려서 한번에 함께 조회함
- 즉시 로딩의 단점
- 예상하지 못한 SQL이 발생
- JPQL에서 N+1문제 발생
📒 @XXXToOne-> default값이 EAGER (LAZY로 변경해야함)
@XXXToMany-> default값이 LAZY
영속성 전이 : CASCADE
- 특정 엔티티를 영속 상태로 만들 때 연관된 엔티티도 함께 영속 상태로 만들고 싶을 때 사용
'JPA' 카테고리의 다른 글
JPA_DataSource (1) | 2023.10.17 |
---|---|
JPA_값 타입 (0) | 2023.10.05 |
JPA_연관 관계 매핑 (0) | 2023.09.23 |
JPA_영속성 컨텍스트 & 객체와 테이블 (0) | 2023.09.19 |