인프런 영문 브랜드 로고
인프런 영문 브랜드 로고

인프런 커뮤니티 질문&답변

이동석님의 프로필 이미지
이동석

작성한 질문수

자바 ORM 표준 JPA 프로그래밍 - 기본편

영속성 전이(CASCADE)와 고아 객체

em.merge 테스트 중에 이해가 되지 않는 현상이 있습니다.

작성

·

129

0

안녕하세요.  merge()에 대해서 의아한 부분이 있어서 질문드립니다. persist()하지 않은 객체의 경우 merge()를 했을 때, 어떤 결과가 나올까 궁금하여 테스트를 해보았습니다.

하지만, 예상했던 결과와는 다르게 동작하고 이런 부분이 이해되지 않기에 질문 드립니다.

 

[엔티티 상태]

Member엔티티(N)

@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "MEMBER_ID")
private Long id;

private String name;

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "TEAM_ID")
private Team team;

// 편의 메소드
public void addTeam(Team team) {
this.setTeam(team);
team.getMembers().add(this);
}

Team엔티티(1)

@Id
@GeneratedValue
@Column(name = "TEAM_ID")
private Long id;

private String name;

// 다대일 양방향
@OneToMany(mappedBy = "team")
private List<Member> members = new ArrayList<>();

 

Main1

public static void main(String[] args) {
EntityManagerFactory emf = Persistence.createEntityManagerFactory("hello");
EntityManager em = emf.createEntityManager();
EntityTransaction tx = em.getTransaction();

tx.begin();
try {
Team team = new Team();
team.setName("TeamA");
em.persist(team);

Member member = new Member();
member.setName("memberA");
member.addTeam(team);
em.persist(member);

em.flush();
em.clear();

/* em.merge() 테스트 */
Team teamB = new Team();
teamB.setName("TeamBB");
em.merge(teamB);
//em.persist(teamB);

System.out.println("merge한 엔티티가 영속성 컨텍스트에 있을까? "+em.contains(teamB)); // false (당연히 원래 컨텍스트에 없던 객체이므로)
Team findTeamB = em.find(Team.class, 3L); // 데이터가 DB에 존재함
System.out.println(findTeamB.getName()); // TeamBB

tx.commit();
} catch (Exception e) {
tx.rollback();

} finally {
em.close();
emf.close();
}
}

- teamB 데이터는 DB에 저장되어있습니다. (findTeamB.getName()이 TeamBB를 반환합니다.)

- teamB는 영속성 컨텍스트에는 존재하지 않습니다.

 

Main2

public static void main(String[] args) {
EntityManagerFactory emf = Persistence.createEntityManagerFactory("hello");
EntityManager em = emf.createEntityManager();
EntityTransaction tx = em.getTransaction();

tx.begin();
try {
/*Team team = new Team();
team.setName("TeamA");
em.persist(team);

Member member = new Member();
member.setName("memberA");
member.addTeam(team);
em.persist(member);

em.flush();
em.clear();*/

/* em.merge() 테스트 */
Team teamB = new Team();
teamB.setName("TeamBB");
em.merge(teamB);
//em.persist(teamB);

System.out.println("merge한 엔티티가 영속성 컨텍스트에 있을까? "+em.contains(teamB)); // false (당연히 원래 컨텍스트에 없던 객체이므로)
Team findTeamB = em.find(Team.class, 3L); // DB에 어떠한 team 데이터도 존재하지 않음
System.out.println(findTeamB.getName()); // 결과 없음

tx.commit();
} catch (Exception e) {
tx.rollback();

} finally {
em.close();
emf.close();
}
}

- team DB에 아무런 데이터도 존재하지 않습니다.

- 영속성 컨텍스트에 역시 teamB는 존재하지 않습니다.

- findTeamB.getName()의 결과는 없습니다. (3L의 키가 아닌것도 맞지만, DB에 애당초 아무런 데이터가 없음)

 

이렇게 Main1과 Main2의 동작에서 어떤 차이가 있기에 이런 결과를 보이는건지 알고싶습니다.

감사합니다.

답변 1

0

김영한님의 프로필 이미지
김영한
지식공유자

안녕하세요. 이동석님

 tx.rollback(); 아래에 다음 코드를 추가해보시고 실행해보시면 문제를 찾을 수 있을거에요.

e.printStackTrace();

감사합니다.

이동석님의 프로필 이미지
이동석

작성한 질문수

질문하기