-
김영한님의 JPA프록시 강의 정리공부/JPA 2023. 1. 2. 15:29
프록시란?
Member 테이블과 Team 테이블의 연관관계. public void printUserandTeam(String memberId) { Member member = em.find(Member.class,memberId); Team team = member.getTeam(); System.out.println("member Name = " + member.getName()); }
Member 테이블과 Team테이블은 서로 연관관계를 맺고 있는 형태이다.
이때 위의 소스코드처럼 getName을 통해 Member테이블의 Name 속성만 조회하고 싶은대
Member 테이블과 Team테이블이 연관관계가 있다고 해서 DB에서 Member 테이블과 연관된 모든 테이블을
DB에서 가져오면 최적화가 잘되지 않은 것이고 성능을 저하시킬 수 있다.
이때 사용하는 것이 프록시이다.
public void printUserandTeam(String memberId) { Member member = em.getReference(Member.class,memberId); Team team = member.getTeam(); System.out.println("member Name = " + member.getName()); //이렇게 실제 사용할때 DB에 쿼리가 나간다. }
em.find가 아닌 em.getReference를 통해 프록시 객체를 member에 저장하겠다고 선언한다.
em.find와는 다르게 DB조회를 하지 않고 가짜 프록시 객체를 member에 저장해 두었다가
member.getName( )과 같이 실제 DB에 데이터를 불러와야 할 때 실제 객체를 조회한다.
실제 클래스를 상속받아서 만들어지게 되고 실제 클래스와 겉모양이 같게 된다.
프록시 객체 초기화
프록시 객체 초기화 과정. 1. 프록시 객체에게 실제 객체를 요청했는데 실제 객체를 참조하고 있는 target 객체가 NULL이라면 초기화를 요청한다.
2. 영속성 컨텍스트가 영속상태인 객체 Member의 실제 값을 DB에 조회해서 실제 Entity를 생성한다
3. 실제 객체를 참조하고 있는 target 객체는 영속성 컨텍스트가 만들어낸 DB에서 조회해서 만들어낸 Entity와 연결된다.
프록시 특징
프록시 객체의 형태 프록시 객체는 객체의 참조를 보관하고 있다. 프록시 객체를 호출하면 프록시 객체는 실제 객체의 메소드를 호출하게 된다.
ex) target.getId( )
Member member1 = new Member(); Member member2 = new Member(); Member m1 = em.find(Member.class,member1.getId()); Member m2 = em.getReference(Member.class,member2.getId()); //m1 ==m2 는 false가 나온다
public void comp(Member m1, Member m2){ }
프록시 객체는 원본 엔티티를 상속받기 때문에 타입 체크 시 주의해야 한다.
== 비교는 두 개의 객체 주소값을 비교하는 연산자인대 m1은 원본 객체를 참조하고 잇고 m2는 프록시 객체이기 때문에
m1 == m2는 false가 되게 된다.
첫 번째 소스코드처럼 getReference 메소드가 보이면 쉽게 구분할 수 있지만
실제 비즈니스 로직은 두 번째 소스코드와 같이 그냥 단순히 두 개의 객체를 매개변수로 전달해서 두개의 값을 비교하게 메소드가 있다면 m1, m2가 프록시 객체인지 진짜 객체인지 알 수 없게 되어 ==을 쓴다면 비교를 실패하게 된다.
아래와 같이 instanceof 메소드를 통해 타입 체크를 해야 한다
public void comp(Member m1, Member m2){ System.out.println(m1 instanceof Member); System.out.println(m2 instanceof Member); }
영속성 컨텍스트에 이미 찾는 엔티티가 존재한다면 getReference( )를 호출해도 실제 엔티티를 반환한다.
Member m1 = em.find(Member.class,member1.getId()); Member m2 = em.getReference(Member.class,member1.getId());
m2가 프록시 객체로 member1의 Id 프록시 객체를 생성하고자 하지만 이미 위에 m1 객체가 member1.getId( )를 통해
객체를 영속성 컨텍스트에 올려놓았기 때문에 m2는 프록시 객체가 아닌 원본 객체가 반환된다.
이미 영속성 컨텍스트에 존재하는 객체를 참조해도 비용적인 측면이 향상되지 않을 뿐더러
m1과 m2는 동일한 영속성 컨텍스트에 등록되어있는 member1의 Id를 조회해서 생성된 객체다.
JPA는 동일성을 지원하기 때문에 member1의 Id를 조회해서 생성된 객체는 모두 같아야 하는데 m2가 프록시 객체가 되어버리면
JPA가 지원하는 동일성 메커니즘이 성립되지 않기 때문에 m2는 원본객체를 반환받게 된다.
'공부 > JPA' 카테고리의 다른 글
3월 17일 공부 값타입 컬렉션 (0) 2023.03.17 3월 14일 공부 (0) 2023.03.15 김영한님의 상속 관계매핑 강의정리 (0) 2022.12.31 JPA annotation 정리 (0) 2022.12.22