JPA getOne(ID), findOne(ID)

JPA 사용 중 Id로 리소스를 조회하는
getOne, findOne 메소드의 차이를 정리한다.

나는 getOne을 이용하여 아래와 같이 로직을 작성하였다.
1. getOne(Id) 로 리소스를 찾는다.
2. null 체크를 통해 존재유무를 확인한다.

존재하지 않는 id를 통해 테스트 시 의도한대로 null체크가 되어야 했지만.
null 체크는 되지 않았으며.
javax.persistence.EntityNotFoundException 이 발생하였다.

But, 같은 역할을 하는 findOne() 메소드를 사용하여 조회했을때는
Exception이 발생하지 않았고, null 체크도 정상적으로 이루어졌다.

API 에 대해 자세히 알려 하지 않고 로직을 작성한 스스로를 반성하며
내용을 정리한다.

getOne과 findOne 메소드의 차이는 간단히 정리하면 다음과 같다.

getOne() 은 lazy-loading 을 통해 객체를 전달한다.
findOne() 은 즉시 조회하여 객체를 전달한다.

왜 getOne() 은 lazy-loading 이후에 Exception을 발생시킬까?
JPA getOne 스펙은 아래와 같다.

getOne

Returns a reference to the entity with the given identifier.

Parameters:id - must not be null.Returns:a reference to the entity with the given identifier.Throws:javax.persistence.EntityNotFoundException - if no entity exists for given id.See Also:EntityManager.getReference(Class, Object)

파라미터 id는 null일수 없고
Id 에 대한 엔티티 참조(프록시를 얘기하는 듯)를 리턴하며,
엔티티가 없을경우 EntityNotFoundException을 던진다.

See Also:EntityManager.getReference(Class, Object)

또한 내부적으로 EntityManager.getReference를 사용하는데.

EntityManager.getReference는 프록시 객체를 리턴한다.
때문에 getOne에서 리턴하는 것도 프록시 객체이고,
getOne()에서 리턴된 객체의 null체크는 의미가 없다.

그렇기 때문에 lazy-loading되는 시점(엔티티 내부 프로퍼티를 참조하는.)에 NotFoundEntityException을 발생하는 것으로 볼 수 있다.

사실 이 NotFoundEntityException도 EntityManager.getReference()로 부터 발생된다.

getReference

Get an instance, whose state may be lazily fetched. If the requested instance does not exist in the database, the EntityNotFoundException is thrown when the instance state is first accessed. (The persistence provider runtime is permitted to throw the EntityNotFoundException when getReference is called.) The application should not expect that the instance state will be available upon detachment, unless it was accessed by the application while the entity manager was open.

Parameters:entityClass - entity classprimaryKey - primary keyReturns:the found entity instanceThrows:IllegalArgumentException - if the first argument does not denote an entity type or the second argument is not a valid type for that entity’s primary key or is nullEntityNotFoundException - if the entity state cannot be accessed

다음은 findOne()의스펙을 보자

파라미터 id는 null이면 안되고,
주어진 id로 엔티티를 리턴하고 또한 못찾는다면 null을 리턴한다,
파라미터 id가 null일 경우 IllegalArgumentException을 던진다.

findOne은 객체를 즉시 조회한다.

실제 객체가 존재한다는 가정하에
객체의 속성에 접근할 필요없이, 엔티티를 맵핑하는 경우에는
getOne을 사용하는 것이 좋다고 생각된다.

참조 :

findOne과 getOne의 차이를 묻는 stackOverFlow
https://stackoverflow.com/questions/33218762/difference-between-crudrepository-findone-and-jparepository-getone

Written by

엘디는 사랑입니다.

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store