@Entity
class Mentoring() {
@Getter
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long Id;
...
}
위와 같은 Metoring 엔티티가 있다.
MentoringService를 테스트할 것이다. Repository들을 전부 주입 받는 대신에 EntityManager를 활용할 것이다.
@Autowired
private MentoringService;
@Autowired
EntityManager em;
...
Mentoring 엔티티의 생성 전략은 IDENTITY이다. DB에 저장하기 전에 id가 null인 Mentoring 객체 를 생성했다. 그대로 mentoring.getId()를 통해 Id를 꺼내오면 당연히 null일 것이다.
Mentoring mentoring = new Mentoring(param1, param2 ...); // no Id parameter
mentoring.getId(); // : null
그렇다면 mentoring 객체 생성 후 이를 persist(), flush()를 통해 mentoring을 DB에 저장하고. 이후 mentoring.getId()를 통해 Id를 가져오면 어떻게 될까?
Mentoring mentoring = new Mentoring(param1, param2 ...);
em.persist(mentoring); // 영속화, 1차 캐싱
em.flush(mentoring); // DB에 반영
mentoring.getId(); // : 1 (not null)
엔티티 생성 전략에 IDENTITY 옵션이 걸려있기 때문에 DB에 저장되면서 ID를 부여받는다. 따라서 null이 아닌 값이 잘 뽑히는 것을 확인할 수 있다. 여기까지는 너무 당연하다.

익숙한 EntityManager의 개념도이다. IDENTITY 는 DB가 값을 쓸 때 ID를 생성하는 전략이기 때문에 실제로 DB에 객체를 저장하는 flush() 실행 시에 insert 쿼리문이 날아가며 객체에 ID가 할당될 것이다.
그렇다면 persist()실행하고 flush()는 실행하지 않았다면 아직 DB에 접근하지 않기 때문에 Id가 null일까?
Mentoring mentoring = new Mentoring(param1, param2 ...);
em.persist(mentoring); // 영속화, 1차 캐싱
mentoring.getId(); // : 1 (not null)
예상과 다르게 persist()만 실행했음에도 insert 쿼리문이 DB에 날아갔고, Id가 할당되었다.
이유는 Hibernate EntityManger의 1차 캐시(영속성 컨텍스트)의 저장 구조가 {EntityKey : Entity} 의 Key -Value Map 구조이기 때문이다.
생성 전략이 IDENTITY인 경우, EntityKey즉, @Id가 존재하지 않는 객체를 persist()하면 EntityManger는key값이 없어 1차 캐시에 엔티티를 저장할 수 없다. 따라서 자동으로 insert 쿼리문을 날린다.
이와 달리 생성 전략이 SEQUENCE 인 경우에는 동일한 상황에서 persist시에 insert 쿼리 대신 select nextval('your_sequence') 쿼리를 통해 id의 시작 인덱스를 받아온다.