TL; DR
T findOne(ID id)
(이전 API의 Optional<T> findById(ID id)
이름 ) / (새 API의 이름)은 엔티티 열망 로딩EntityManager.find()
을 수행하는 데 의존 합니다 .
T getOne(ID id)
에 의존 EntityManager.getReference()
하는 수행하는 개체 지연로드 . 따라서 엔티티를 효과적으로로드하려면 메소드를 호출해야합니다.
findOne()/findById()
보다 더 명확하고 사용하기 쉽습니다 getOne()
.
따라서 대부분의 경우을 선호 findOne()/findById()
합니다 getOne()
.
API 변경
최소한 2.0
버전이 Spring-Data-Jpa
수정되었습니다 findOne()
.
이전에는 CrudRepository
인터페이스 에서 다음 과 같이 정의 되었습니다.
T findOne(ID primaryKey);
이제, findOne()
당신이 찾게 될 유일한 방법 CrudRepository
은 QueryByExampleExecutor
인터페이스 에서 다음 과 같이 정의 된 것입니다 :
<S extends T> Optional<S> findOne(Example<S> example);
인터페이스 SimpleJpaRepository
의 기본 구현 인에 의해 마침내 구현 CrudRepository
됩니다.
이 방법은 예제 검색에 의한 쿼리이며 대체 방법으로 원하지 않습니다.
실제로 동일한 동작을 가진 메소드가 여전히 새 API에 있지만 메소드 이름이 변경되었습니다.
그것은에서 이름이 바뀌 었 findOne()
에 findById()
의 CrudRepository
인터페이스 :
Optional<T> findById(ID id);
이제는를 반환합니다 Optional
. 어느 것이 예방하기에 나쁘지 않습니다 NullPointerException
.
그래서, 실제 선택은 사이에 지금 Optional<T> findById(ID id)
과 T getOne(ID id)
.
두 개의 고유 한 JPA EntityManager 검색 메소드에 의존하는 두 개의 고유 한 메소드
1) Optional<T> findById(ID id)
javadoc은 다음과 같이 말합니다.
ID로 엔티티를 검색합니다.
구현을 살펴보면 EntityManager.find()
검색을 수행 하는 데 의존한다는 것을 알 수 있습니다 .
public Optional<T> findById(ID id) {
Assert.notNull(id, ID_MUST_NOT_BE_NULL);
Class<T> domainType = getDomainClass();
if (metadata == null) {
return Optional.ofNullable(em.find(domainType, id));
}
LockModeType type = metadata.getLockModeType();
Map<String, Object> hints = getQueryHints().withFetchGraphs(em).asMap();
return Optional.ofNullable(type == null ? em.find(domainType, id, hints) : em.find(domainType, id, type, hints));
}
그리고 여기 em.find()
에 EntityManager
선언 된 방법이 있습니다 :
public <T> T find(Class<T> entityClass, Object primaryKey,
Map<String, Object> properties);
javadoc 상태 :
지정된 속성을 사용하여 기본 키로 찾기
따라서로드 된 엔티티 검색이 예상됩니다.
2) T getOne(ID id)
javadoc 상태 (강조는 내 것) :
주어진 식별자를 가진 엔터티에 대한 참조 를 반환합니다 .
실제로 참조 용어는 실제로 보드이며 JPA API는 getOne()
메소드를 지정하지 않습니다 .
따라서 Spring 래퍼가하는 일을 이해하기 위해 가장 좋은 방법은 구현을 조사하는 것입니다.
@Override
public T getOne(ID id) {
Assert.notNull(id, ID_MUST_NOT_BE_NULL);
return em.getReference(getDomainClass(), id);
}
다음과 같이 선언 em.getReference()
된 EntityManager
메소드가 있습니다.
public <T> T getReference(Class<T> entityClass,
Object primaryKey);
그리고 다행히도 EntityManager
javadoc은 의도를 더 잘 정의했습니다 (강조는 내 것입니다).
상태가 느리게 페치 될 수있는 인스턴스를 가져옵니다 . 요청 된 인스턴스가 데이터베이스에 없으면 인스턴스 상태에 처음 액세스 할 때 EntityNotFoundException이 발생 합니다 . 지속성 제공자 런타임은 getReference가 호출 될 때 EntityNotFoundException을 발생 시킬 수 있습니다 . 애플리케이션은 엔티티 관리자가 열려있는 동안 애플리케이션이 액세스하지 않는 한 분리시 인스턴스 상태가 사용 가능할 것으로 예상해서는 안됩니다 .
따라서 호출 getOne()
하면 느리게 가져온 엔티티를 리턴 할 수 있습니다.
여기서 게으른 인출은 엔터티의 관계가 아니라 엔터티 자체의 관계를 나타냅니다.
이는 우리가 호출 getOne()
한 다음 지속성 컨텍스트가 닫히면 엔티티가로드되지 않아 결과를 실제로 예측할 수 없음을 의미합니다.
예를 들어 프록시 객체가 직렬화 된 null
경우 직렬화 된 결과로 참조를 가져 오거나 프록시 객체에서 메소드가 호출 된 경우 예외 LazyInitializationException
가 발생합니다.
따라서 이러한 상황에서는 엔터티가 존재하지 않는 동안 오류 상황이 수행되지 않을 수 있기 때문에 데이터베이스에 존재하지 않는 인스턴스를 처리하는 EntityNotFoundException
데 사용되는 주된 이유 getOne()
입니다.
어쨌든 로딩을 보장하려면 세션이 열린 상태에서 엔티티를 조작해야합니다. 엔티티에서 메소드를 호출하여이를 수행 할 수 있습니다.
또는 findById(ID id)
대신 더 나은 대안 사용 .
왜 그렇게 불분명 한 API입니까?
마무리하기 위해 Spring-Data-JPA 개발자에게 두 가지 질문이 있습니다.