
https://github.com/ryanproback/jpa-id-gen-test
@Getter
@Entity
@Table(name = "test_entity")
public class TestEntity {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
}
@PersistenceUnit
EntityManagerFactory entityManagerFactory;
@Test
public void test() {
EntityManager entityManager =
entityManagerFactory.createEntityManager();
TestEntity entity = new TestEntity();
entityManager.getTransaction()
.begin();
entityManager.persist(entity); // persist!
assertThat(entity.getId()).isNotNull();
entityManager.getTransaction()
.commit();
assertThat(entity.getId()).isNotNull();
entityManager.close();
}
EntityManager 의 구현체는 SessionImpl 이다. (Proxy 객체로 랩핑되어 있지만, 다루지 않는다.)
entityManager.persist() 호출시 SessionImpl에서 Override한 메소드가 호출된다.


fastSessionServices.eventListenerGroup_PERSIST.listeners 에 있는 리스너는 DefaultPersistEventListener 이다.


아직 Persist되지 않은 Entity의 상태는 TRANSIENT로 표현된다.
따라서 내부 메소드인 entityIsTransient 가 호출된다.
EntityState 판별은 여기서 다루지 않겠다.
대충 요약하면, 아직 PK가 존재하지 않기 때문에 TRANSIENT로 판별된다.
DETACHED : Persist된 적이 있고, 영속성 컨텍스트에 존재하지 않음.
PERSISTENT : Persist된 적이 있고, 영속성 컨텍스트에 존재함.
TRANSIENT : Persist된 적이 없으며, 영속성 컨텍스트에 존재하지 않음.

createCache의 타입은 Map이다. createCache 는 onPersist에서 새로 생성된다.
아래와 같은 이유로 createCache.put은 null을 반환하므로 saveWithGeneratedId() 가 호출된다.
the previous value associated with key, or null if there was no mapping for key.
DefaultPersistEventListener 는 AbstractSaveEventListener를 상속하고 있다. saveWithGeneratedId()는 AbstractSaveEventListener 에 구현되어 있다.



source.getActionQueue().addAction(insert) 호출 시점에 DB로 INSERT SQL을 보낸다.
좀 더 파고들어가면 hibernate의 ActionQueue 에서 insert sql을 execute 하는 부분이 나오는데,
이쯤이면 궁금증은 충분히 풀어서 마친다 :)