✔ 엔티티 비교

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

영속성 컨텍스트를 통해 데이터를 저장하거나 조회하면 1차 캐시에 엔티티가 저장된다. 1차 캐시 덕분에 변경 감지 기능도 동작하고, 이름 그대로 1차 캐시로 사용되어 DB를 통하지 않고 데이터를 바로 조회할 수도 있다.

영속성 컨텍스트를 더 정확히 이해하기 위해서는 1차 캐시의 가장 큰 장점인 애플리케이션 수준의 반복 가능한 읽기를 이해해야 한다. 같은 영속성 컨텍스트에서 엔티티를 조회하면 항상 같은 엔티티 인스턴스를 반환한다. 동등성 비교 수준이 아니라 정말 주소값이 같은 인스턴스를 반환한다.

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

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

테스트와 트랜잭션 범위

아래 테스트 코드는 트랜잭션 안에서 시작하므로 테스트의 범위와 트랜잭션의 범위가 같다.

따라서 테스트 전체에서 같은 영속성 컨텍스트에 접근한다.

@RunWith(SprignJunit4ClassRunner.class)@ContextConfiguration(loactions = "classpath:appConfig.xml")@Transactional //트랜잭션 안에서 테스트를 실행public class MemberServiceTest{    @Autowired    MemberService memberService;    @Autowired    MemberRepository memberRepository;    @Test    public void register() throws Exception{        //Given        Member member = new Member("kim");        //When        Long saveId = memberService.join(member);        //Then        Member findMember = memberRepository.findOne(saveId);        assertTrue(member == findMember); //참조값 비교    }}@Service@Transactionalpublic class MemberService{    @Autowired    MemberRepository memberRepository;    public Long join(Member member){        memberRepository.save(member);        return member.getId();    }}@Repositorypublic class MemberRepository{   @PersistenceContext   EntityManager em;    public void save(Member member){        em.persist(member);    }    public Member findOne(Long id){        return em.find(Member.class, id);    }}

테스트 클래스에 @Transactional가 선언되면 트랜잭션을 먼저 시작하고 테스트 메소드를 실행한다.

따라서 테스트 메소드인 register()는 이미 트랜잭션 범위에 들어 있고 이 메소드가 끝나면 트랜잭션이 종료된다.

그러므로 register()에서 사용된 코드는 항상 같은 트랜잭션과 같은 영속성 컨텍스트에 접근한다.

코드를 보면 회원을 생성하고 memberRepository에서 em.persist(member)로 회원을 영속성 컨텍스트에 저장한다. 그리고 저장된 회원을 찾아 저장한 회원과 비교한다.

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

저장한 회원과 회원 리포지토리에서 찾아온 엔티티가 완전히 같은 인스턴스인데 같은 트랜잭션 범위에 있어 같은 영속성 컨텍스트를 사용하기 때문이다.