프록시란?
Hibernate 프록시
- JPA 표준 스펙에 프록시와 관련된 내용은 없다
- JPA의 구현체인 Hibernate의 기능
사용 이유
- DB에서 Member 테이블만 조회할 때 의미 없이 다른 테이블 JOIN을 걸지 않듯이, JPA에서도 Member만 조회할 때 Team을 같이 조회한다면 성능 면에서 손해
- 무의미한 쿼리를 줄여 성능을 향상시키기 위해 사용한다
Hibernate 프록시 작동 방식
entityManager.find()
: 실제 Entity 쿼리
entityManager.getReference()
: 프록시 객체를 통한 쿼리
- Hibernate 프록시는 실제 Entity를 상속받는다
- 타입 체크할 때 ==로 비교하면 실패하므로 instanceof로 비교
- 프록시 객체 내부에는 상속받은 원본 Entity 필드(비어있음)가 존재한다
- 처음으로 프록시 객체를 사용하는 시점(getter 등으로 ID를 제외한 필드를 호출하는 시점)에 원본 Entity가 초기화된다
- 비어있는 Entity 필드에 DB에서 쿼리한 Entity 연결
- 이후 프록시 객체는 DB에서 쿼리한 Entity 객체 참조
- 실제 Entity 객체에 접근 가능
- (중요) 프록시 객체가 영속성 컨텍스트의 관리를 벗어났을 때 초기화하면 LazyInitializationException 발생
- 프록시 객체가 영속 상태가 아니게 된 경우
- 영속성 컨텍스트가 닫힌 경우
- 영속성 컨텍스트에 이미 Entity가 있으면
getReference()
를 사용해도 실제 Entity 반환
- 이미 1차 캐시에 Entity가 들어있는데 프록시를 쓸 이유가 전혀 없기 때문
- JPA에서 하나의 트랜잭션 내에서 조회한 같은 객체는 == 으로 비교했을 때 true가 나와야 함
- 영속성 컨텍스트에 프록시가 먼저 올라가 있으면
find()
를 사용해도 프록시 반환
- JPA에서 하나의 트랜잭션 내에서 조회한 같은 객체는 == 으로 비교했을 때 true가 나와야 함
프록시 확인, 초기화
- 프록시 인스턴스 초기화 여부 확인
entityManagerFactory.getPersistenceUnitUtil().isLoaded(entity)
- 프록시 클래스 확인
entity.getClass().getName()
- 프록시 강제 초기화
Hibernate.initialize(entity)
- JPA 표준 기능이 아닌 Hibernate의 기능