Close
Close full mode
logo만렙 개발자 키우기

(2) 엔티티 비교

Git RepositoryEdit on Github
Last update: a year ago by nowwaterReading time: 2 min

영속성 컨텍스트 내부엔 엔티티 인스턴스를 보관하기 위한 1차 캐시가 있고, 이는 영속성 컨텍스트와 생명주기가 같다.

영속성 컨텍스트를 통해 데이터 저장/조회 시 1차 캐시에 엔티티가 저장. 이를 통해 변경 감지 기능도 동작하고, DB를 통하지 않고 데이터를 바로 조회 가능

1차 캐시의 가장 큰 장점애플리케이션 수준의 반복 가능한 읽기 이다.

같은 영속성 컨텍스트에서 엔티티를 조회하면 다음 코드와 같이 항상 같은 엔티티 인스턴스를 반환 (동등 비교(equals) 가 아닌 주소값이 같은 인스턴스를 반환)

Member member1 = em.find(Member.class, 1L);
Member member2 = em.find(Member.class, 1L);
assertTrue(member1 == member2); // 둘이 같은 인스턴스다.

15.2.1 영속성 컨텍스트가 같을 때 엔티티 비교

image

영속성 컨텍스트가 같으면 엔티티를 비교할 때 다음 3가지 조건을 만족한다.

  • 동일성 : == 비교

  • 동등성 : equals() 비교

  • 데이터베이스 동등성 : @Id 인 데이터베이스 식별자가 같다.

Member findMember = memberRepository.findOne(saveId);
assertTrue(member == findMember); // 참조값 비교 - true

기본 전략은 먼저 시작된 트랜잭션이 있으면 그 트랜잭션을 그대로 이어 받아 사용하고, 없으면 새로 시작한다.

테스트 클래스에 @Transactional 적용 시 트랜잭션을 커밋하지 않고 트랜잭션을 강제로 롤백한다.

하지만 롤백 시 영속성 컨텍스트를 플러시하지 않아 어떤 SQL이 실행되는지 콘솔 로그에 남지 않는다.


15.2.2 영속성 컨텍스트가 다를 때 엔티티 비교

테스트 클래스에 @Transactional이 없고, 서비스에만 @Transactional이 있으면 다음과 같은 트랜잭션 범위와 영속성 컨텍스트 범위를 갖는다.

image

Member member = new Member("kim");
Long saveId = memberService.join(member);
Member findMember = memberRepository.findOne(saveId); // 리포지토리의 트랜잭션에서 조회한 엔티티를 반환
assertTrue(member == findMember); // 참조값 비교 - false : 테스트 클래스에서 조회한 member와 리포지토리에서 조회한 findMember는 서로 다른 인스턴스

image

테스트 코드에서 회원가입하여 만든 Member는 서비스 계층의 트랜잭션, 이후 레포지토리에서 조회한 Member는 레포지토리 계층의 트랜잭션을 사용함
=> 서로 다른 영속성 컨텍스트를 갖는다.

memberfindMember는 인스턴스는 다르지만 같은 데이터베이스 로우를 가르키고 있어서 사실상 같은 엔티티다.

동일성 비교

  • 영속성 컨텍스트에 따라서 동일성 비교(==) 로 엔티티를 비교할 수 있을 수도 있고 아닐 수도 있다.

  • (OSIV 는 동일성 비교로 가능, 하지만 영속성 컨텍스트가 달라진다면 동일성 비교로는 불가능)

데이터베이스 동등성 비교

  • 엔티티를 영속화해야 식별자를 얻을 수 있다는 문제가 있다. (엔티티 영속화 전에는 식별자 값이 null)

  • 직접 부여하는 방식에는 데이터베이스 식별자 비교도 가능하다.

  • 하지만 항상 식별자를 먼저 부여하는 것을 보장하기는 쉽지 않다.

동등성 비교

  • 엔티티 비교 시 비즈니스 키를 활용한 동등성 비교를 권장. (equals())

  • equals() 오버라이딩 시 비즈니스 키가 되는 필드를 선택. -> 보통 중복되지 않고 거의 변하지 않는 데이터베이스 기본 키 후보들이 좋은 대상.

    유일성만 보장되면 가끔 있는 변경 정도는 허용

    ex) 회원 엔티티에 이름과 연락처가 같은 회원이 없다면 (회원 이름 + 연락처) 정도만 조합해서 사용 가능

정리

동일성 비교 : 같은 영속성 컨텍스트의 관리를 받는 영속 상태의 엔티티에만 적용 가능

동등성 비교 : 다른 영속성 컨텍스트의 관리를 받는다면, 유일한 비즈니스 키를 사용해 엔티티 비교

🚀 JPA — Previous
(1) 예외 처리
Next — 🚀 JPA
(3) 프록시 심화 주제