요약
repository.getReferenceById()
를 이용해 프록시 객체를 생성하고, 엔티티 생성 parameter에 엔티티 대신 넘긴다getReferenceById()
는 JPA에 정의되어 있기 때문에 구현 없이 쓰면 된다- 프록시 객체는 Primary key(id) 만 초기화되어 있고, 다른 값은 모두 null인 객체이다
설명
Foreign Key가 있는 레코드를 생성할 때, DBMS에서는 Foreign Key(user_id 등)만 알면 INSERT
문으로 레코드를 생성할 수 있다. 그러나 이를 JPA 코드로 표현하면 FK 뿐만 아니라 관계된 전체 객체가 필요한 것처럼 보인다.
Habit habit = Habit.creationBuilder()
.runTime(param.getRunTime().toLocalTime())
.place(param.getPlace())
.action(param.getBehavior())
.value(param.getBehaviorValue())
.unit(param.getBehaviorUnit())
// 전체 엔티티를 입력해야 한다
// DBMS처럼 userId만 가지고는 Habit을 생성할 수 없을까?
.user(user)
.build();
이 문제를 해결하기 위해서 제시된 개념이 JPA의 프록시 객체이다. UserRepository의 getReferenceById(userId)
를 호출하면 id
만 초기화되어 있는 프록시 객체를 반환한다. 타입이 Entity(User
)이기 때문에 위 코드에 적용할 수 있다. 그러나 getReferenceById()
는 find()
와 다르게 SELECT
를 수행하지 않는 장점이 있다. 관계된 엔티티를 생성할 때는 User SELECT 없이 FK만 입력하면 되므로 이럴 때 사용하면 불필요한 SQL 연산을 줄일 수 있다. 그러나, 다른 필드를 요쳥하면 지연 로딩(SELECT)하므로 유의해야 한다. 프록시 객체임을 명시해야 잘못된 의도로 사용되지 않을 것 같다.
프록시 패턴
같은 인터페이스를 쓰는 객체를 만들어서 원본 객체에 접근하는 것을 제어하기 위한 디자인 패턴이다. 프록시 객체 메소드가 원본 객체 메소드를 wrapping하고 있어서, 원본 메소드를 호출하기 전,후에 프록시 메소드의 로직을 실행한다고 생각하면 된다. Lazy initialization, 권한 확인 후 접근 제어, 캐싱, 로깅 등에 사용한다
프록시 객체와 프록시 패턴
JPA에서 FK만 있는 객체를 프록시 객체라고 부르는 이유는 엔티티와 같은 타입(인터페이스)를 가지고 있고, DB 조회를 막기(제어)위한 목적을 가지고 있기 때문으로 추정된다
참고 자료
https://www.baeldung.com/jpa-entity-manager-get-reference
https://refactoring.guru/design-patterns/proxy
'Spring Framework' 카테고리의 다른 글
[MapStruct] 필드 매핑할 때 다른 Mapper 클래스의 메소드 사용하는 법 - uses, @Named (0) | 2024.08.07 |
---|---|
[Spring][스크랩] nested transaction의 동작 방식 (0) | 2024.08.02 |
[Spring] DTO의 사용 범위, 목적, Mapper (0) | 2024.07.12 |
객체 지향 설계와 스프링 프레임워크 (0) | 2024.05.24 |
좋은 객체 지향 프로그래밍이란? - 다형성 (0) | 2024.05.23 |