작성
·
412
답변 1
4
안녕하세요.
같은 강의를 듣고 공부하고 있는 지나가던 나그네 입니다.
제가 공부한 내용을 토대로 답변을 한 번 드려보려고 합니다.
말씀주신 질문을 토대로 테스트 코드를 아래처럼 작성해봤습니다.
@Test
@DisplayName("member - team 테스트")
void memberTeamTest() {
Team team = new Team();
team.setName("team1");
em.persist(team);
Member member = new Member();
member.setName("member1");
member.setTeam(team);
em.persist(member);
// 아래 flush 와 clear 는 실제 insert 쿼리를 확인해보기 위해 추가했습니다.
em.flush();
em.clear();
assertThat(member.getId()).isNotNull();
}
먼저 아래처럼 em.persist(team) 만 em.persist(member) 아래로 내려도 실제 동작 수행에는 크게 문제가 되지 않습니다.
@Test
@DisplayName("member - team 테스트")
void memberTeamTest() {
Team team = new Team();
team.setName("team1");
Member member = new Member();
member.setName("member1");
member.setTeam(team);
em.persist(member);
em.persist(team);
// 아래 flush 와 clear 는 실제 insert 쿼리를 확인해보기 위해 추가했습니다.
em.flush();
em.clear();
assertThat(member.getId()).isNotNull();
}
하지만, 실제로 테스트를 실행해보면 update 쿼리가 하나 더 실행되실 겁니다.
이유는 영속성 컨텍스트에 데이터가 생성되는 시점이 달라서 인데요.
em.persist 는 객체를 영속성 컨텍스트에 영속화 하게 되는데, member를 먼저 영속화 하는 경우,
team 객체가 영속화 되어있지 않은 상태이기 때문에, team 객체에 id가 없습니다.
영속성 컨텍스트 내 1차캐시 상황을 그려보면 아래와 같을 것으로 예상이 되는데요.
자바 상에서 team 이라는 객체는 생성됐지만, EntityManager에 의해 영속화 되기 전이기 때문에 id 는 null로 들어가게 될 것으로 예상됩니다.
그 다음에 team 을 영속화 하게 되면 아래처럼 1차 캐시가 변경될 것 입니다.
이 상태에서 member 객체 내에 있는 team 객체가 영속화가 되었으니, team id 가 생성되었으므로
member가 참조하는 team에도 해당 id를 부여할 것으로 예상됩니다. 따라서 아래처럼 다시 1차캐시가 바뀌게 될 것입니다. ( 같은 트랜잭션 내에서 발생되어 변경감지로 간주되는 것으로 예상됩니다.)
이 경우 에서 1차캐시에 있는 내용을 DB에 반영하면 SQL이 순차적으로 아래 처럼 발생하게 됩니다.
INSERT INTO member(id, name, member_id) VALUES(1, "member1", null);
INSERT INTO team(id, name) VALUES(2, "team1");
UPDATE member SET team_id = 2 WHERE id = 1;
즉, 연관관계가 맺어져 있는 entity를 insert 하는 경우, 외래키를 가지는 연관관계의 주인을 나중에 insert 해야 insert 쿼리 2개가 발생하고,
질문 주신대로 순서를 바꿔서 persist 하는 경우에는 결과적으로 반영되는 데이터는 동일할지라도update 쿼리가 한 번 더 발생해서 3번의 쿼리가 발생되게 됩니다.
쿼리 2번이면 될 작업을 굳이 쿼리 3번으로 할 필요는 없겠죠? 이러한 이유 때문에 team 을 먼저 persist 하고 member 를 나중에 persist 한 것으로 예상됩니다.
저도 JPA 를 공부하는 입장이라 신뢰성(?)은 다소 떨어질 수 있지만, 제가 공부한 내용과 실제 테스트코드를 돌려본 결과로 인해 도출된 결과를 답변드리니 공부하실 때 참고되셨으면 좋겠습니다.
(혹시 영한님께서 이 답변을 보신다면.... 제 답변에 잘못된 내용 지적해주시면 감사드리겠습니다...!)