JPA 에서 getById vs findById

eden·2021년 10월 20일
0

spring

목록 보기
1/3

문제점

평소 JPA를 사용하면서 getById와 findById를 혼용해서 사용 하였다.
명확한 차이점을 이해하지 못하고 혼용해서 사용했기에
이번 기회에 알아보려고 한다.

getById vs findById

  • 1.SimpleJpaRepository.getById(Id id)

	@Override
	public T getById(ID id) {

		Assert.notNull(id, ID_MUST_NOT_BE_NULL);
		return em.getReference(getDomainClass(), id);
	}
  • 1-1) getById안 em.getReference()
em.getReference(getDomainClass(), id)
  • 1-2)EntityManager.getReference()

EntityManager 인터페이스의 getReference()부분 주석이다.

1.주요 내용을 보면 인스턴스의 상태를 느리게 가져올 수 있는 객체를 가져온다.
2.인스턴스가 데이터베이스에 존재하지 않는 경우 EntityNotFoundException이 발생한다.

이중 1번 내용인 인스턴스의 상태를 느리게 가져올 수 있는 객체를 가져온다는건 프록시 객체를 가져온다는 것을 의미한다.
여기에서 말하는 프록시 객체는 식별자와 실제 객체의 주소를 가지고 있는 객체이며,
실제 객체의 식별자를 제외한 상태에 접근 또는 변경할때에 프록시 객체를 통하여 실제 객체로 접근한다.



  • 2.SimpleJpaRepository.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 = new HashMap<>();
getQueryHints().withFetchGraphs(em).forEach(hints::put);

return Optional.ofNullable(type == null ? em.find(domainType, id, hints) : em.find(domainType, id, type, hints));

findById의 경우 실제 데이터베이스에 접근하여 실제 객체를 반환 받으며 엔티티가 존재하지 않는경우
IllegalArgumentException 을 발생시킨다.

getById는 정말 데이터베이스에 바로 접근하지 않는가?

@GetMapping("/api/test")
    public void testGetByFindBy() {
        userRepository.getById(1L);
        System.out.println("---first---");
        userRepository.findById(1L);
        System.out.println("---second---");
    }

위 코드를 실행해봤을 때에 올라오는 로그

---first---
Hibernate: select user0_.id as id1_8_0_, user0_.created_date as created_2_8_0_, user0_.modified_date as modified3_8_0_, user0_.birth as birth4_8_0_, user0_.deleted_yn as deleted_5_8_0_, user0_.fcm_token as fcm_toke6_8_0_, user0_.finish_ban_date as finish_b7_8_0_, user0_.name as name8_8_0_, user0_.oauth_id as oauth_id9_8_0_, user0_.provider as provide10_8_0_, user0_.push_yn as push_yn11_8_0_ from user user0_ where user0_.id=?
---second---

@GetMapping("/api/test")
    public User testGetByFindBy() {
        System.out.println("---first---");
        User byId = userRepository.getById(1L);
        System.out.println("---second---");
        return byId;
    }

위 코드를 실행해봤을 때에 올라오는 로그

---first---
---second---
Hibernate: select user0_.id as id1_8_0_, user0_.created_date as created_2_8_0_, user0_.modified_date as modified3_8_0_, user0_.birth as birth4_8_0_, user0_.deleted_yn as deleted_5_8_0_, user0_.fcm_token as fcm_toke6_8_0_, user0_.finish_ban_date as finish_b7_8_0_, user0_.name as name8_8_0_, user0_.oauth_id as oauth_id9_8_0_, user0_.provider as provide10_8_0_, user0_.push_yn as push_yn11_8_0_ from user user0_ where user0_.id=?

return 때 해당 객체가 직렬화 되면서 내부적으로 getter함수가 호출 될때에 실제 객체의 함수를 호출하여 데이터베이스에 접근 하기 때문에 위와같은 로그가 찍히게 된다.

그래서 언제 어떤걸 써야 하는데?

엔티티의 실제 상태값이 필요하지 않고 식별자가 필요하거나 참조를 통한 연관관계 매핑용으로는 getById를 사용하는게 맞고,
엔티티의 실제 상태값이 필요한 경우에는 데이터베이스에 접근하여 실제 객체를 생성하는 findById를 사용하는게 맞다고 생각한다.

참고) https://www.javacodemonk.com/difference-between-getone-and-findbyid-in-spring-data-jpa-3a96c3ff

profile
다양한 것에 관심있는 개발자입니다.

0개의 댓글