JPA

테스트를 통해 JPA Entity 영속성에 대해 알아보자 (1)

자바지기 2022. 8. 29. 17:49
반응형

예시로 사용된 코드는 깃허브를 통해 확인할 수 있습니다. 

 

모락 프로젝트를 진행하면서 다양한 상황에서 영속성이 어떻게 적용되는지에 대해 정확하게 알지 못하고 JPA를 사용해왔습니다.

따라서 테스트를 통해 영속성에 대한 학습을 진행해보았고 헷갈리는 부분에 대해 정리해볼 수 있었습니다.

1편에서는 EntityManager의 persist 메서드에 대해, 2편에서는 merge 메서드에 대해 다룰 예정입니다.

 

 

테스트는 아래의 Member Entity를 이용하여 진행하였습니다.

테스트를 위한 Entity

 

1.  save 하려는 Entity 객체와 save 후 반환되는 Entity 객체는 동일한 객체일까?

다음의 테스트를 통해 살펴보겠습니다.

위의 테스트는 통과합니다.

save 하려고 만든 멤버 객체와 save 후 반환되는 저장된_멤버 객체가 동일함을 알 수 있습니다.

 

여기서 한 가지 의문이 있었습니다.

 

멤버 객체는 생성 시 id 필드에 null이 존재할 것이고, 저장된_멤버 객체는 id 필드에 값이 존재할 것입니다.

이런 상황에서 어떻게 동일한 객체가 되었는지 궁금했습니다.

 

답은 SimpleJpaRepository 클래스의 save 메서드에서 찾을 수 있었습니다.

MemberRepository는 JpaRepository를 상속받습니다. 

SimpleJpaRepository는 JpaRepository를 상속받으면 가지고 오게 되는 구현체입니다.

 

SimpleJpaRepository의 save 메서드를 확인해보겠습니다.

 

if 문을 자세히 살펴보겠습니다.

if (entityInformation.isNew(entity)) {
   em.persist(entity);
   return entity;
} 

entityInformation.isNew(entity)를 만족한다면 전달받은 entity를 그대로 반환해주는 구조입니다.

entityInformation.isNew(entity)는 디버깅을 통해 알아본 결과, entity 내부에 id 값이 존재하는지에 대한 여부였습니다.

우리가 생성해준 멤버 Entity에는 id 값이 null이었으므로 true를 반환하게 됩니다.

 

if 문 내부에서는 다음과 같이 실행됩니다.

 

Entity가 영속성을 갖게될 때, 즉 em.persist(entity)를 실행할 때 Entity 내부의 id 값이 채워집니다.

결론적으로 save의 parameter로 전달한 Entity는 id 필드가 채워지고 반환되는 것을 확인할 수 있었습니다!!

 

2.  그렇다면 id 필드는 어느 시점에 채워지는 것일까?

위의 테스트에서 Entity를 save 할 때 어느 시점에 id 값이 채워지는지 궁금했습니다.

 

두 가지 상황을 생각해보았습니다.

1. DB에서 자동으로 생성될 id를 조회 ->  Entity id 필드에 그 값을 주입 ->  Entity를 db에 insert -> Entity 반환

2. id가 존재하지 않는 Entity를 db에 insert -> insert 결과를 조회 -> 조회로 얻은 id를 Entity에 삽입하여 반환

 

답을 찾아내기 위해 위와 동일한 테스트를 디버깅해보았습니다.

 

디버깅 결과는 다음과 같습니다.

 

1. id가 존재하지 않는 Entity를 DB에 insert 한다.

 

EntityIdentityInsertAction의 84번 줄을 확인해보겠습니다.

 

persister.insert() 메서드는 instance를 insert 하고 결과로 generatedId를 반환합니다. 

이때의 instance 상태는 다음과 같습니다. id에는 null이 존재합니다. 

이후 90번 줄을 확인해보면, persister.setIdentifier( instance, generatedId, session )를 실행합니다.

즉, 84번 줄에서 얻은 generatedId를 reflection을 통해 instance에 삽입해줍니다.

 

90번 줄을 실행한 뒤, instance의 상태는 다음과 같습니다.

 

결론적으로 정리를 해보자면,

1. id가 존재하지 않는 Entity를 db에 insert 한다.

2. insert를 통해 얻은 id값을 Entity에 넣어준다.

3. Entity를 반환한다. 

 

em.persist 메서드는 위의 순서로 진행됨을 알 수 있었습니다.

 

 

 

모락 깃허브 : https://github.com/woowacourse-teams/2022-mo-rak

반응형