twocowsong

병합 merge 본문

IT/JPA

병합 merge

WsCode 2022. 5. 7. 13:05

깃허브 정리 URL : https://github.com/sWineTake/jpa.git

 

GitHub - sWineTake/jpa: 자바 ORM 표준 JPA 프로그래밍 - 김영한

자바 ORM 표준 JPA 프로그래밍 - 김영한. Contribute to sWineTake/jpa development by creating an account on GitHub.

github.com

준영속 상태의 엔티티를 다시 영속 상태로 변경하려면 병합을 사용하면 됩니다.

merge() 메소드는 준영속 상태의 엔티티를 받아서 그정보로 새로운 영속 상태의 엔티티를 반환합니다.

 

...
tx.commit();
em.close();

Member mergeMember = em.merge(memberA);

해당 소스코드를 시작전 persistence.xml 에서 DB를 Mysql로 변경하였습니다. 깃에서 확인 부탁드립니다.


준영속 상태의 엔티티를 영속상태로 변경하는 예제 소스코드입니다.

파일 이름은 ExamMergeMain.java 입니다.

 

public class ExamMergeMain {

   static EntityManagerFactory emf =
         Persistence.createEntityManagerFactory("jpa-study");

   public static void main(String[] args) {
      Member member = createMeber("memberA", "username1", 20);

      member.setUsername("회원 명 변경");

      mergeMember(member);
   }

   static Member createMeber(String id, String username, int age) {
      // 영속성 컨텍스트1 시작 //
      EntityManager em1 = emf.createEntityManager();
      EntityTransaction tx1 = em1.getTransaction();

      // 엔티티 생성
      Member member = new Member(id, username, age);

      // 영속성 컨텍스트에 엔티티 등록
      tx1.begin();
      em1.persist(member);
      tx1.commit();

      em1.close(); // 영속성 컨텍스트 1 종료
                // member 엔티티는 준영속 상태가 됩니다.

      // 영속성 컨텍스트 1 종료 //
      return member;
   }

   static void mergeMember(Member member) {
      EntityManager em2 = emf.createEntityManager();
      EntityTransaction tx2 = em2.getTransaction();

      tx2.begin();
      // 준영속 상태의 member를 영속상태의 mergeMember로 리턴합니다.
      Member mergeMember = em2.merge(member);
      tx2.commit();

      // 준영속 상태
      System.out.println("member = " + member.getUsername());

      // 영속 상태
      System.out.println("mergeMember = " + mergeMember.getUsername());

      System.out.println("em2 contains member = " + em2.contains(member));
      System.out.println("em2 contains mergeMember = " + em2.contains(mergeMember));

      em2.close();
   }

}

출력 결과는 아래와 같습니다.

member = 회원 명 변경
mergeMember = 회원 명 변경
em2 contains member = false
em2 contains mergeMember = true

소스코드의 상세 설명은 아래와 같습니다.

1. main 메소드에서 createMember를 호출하여 DB에 insert 후 close를 호출하여 준영속상태가 됩니다.

2. 준영속 상태의 member엔티티를 리턴받아 setUsername을 호출하여 이름을 변경합니다.

3. mergeMember 메소드에서 엔티티 매니저에서 merge함수를 호출하여 준영속 상태의 member를 영속 상태의 mergeMember 엔티티를 생성합니다.

4. mergeMember는 새로운 영속 상태의 엔티티입니다. 트랜잭션 커밋시 수정했던 회원명이 DB에 반영이 됩니다.

 

 

merge()를 좀더 자세히 알아보면 아래와 같습니다.

1. em2.merge(member); 를 실행합니다.

2. 파라미터로 넘어온 준영속 상태에 엔티티의 식별자 값으로 1차 캐시에서 엔티티를 조회합니다.

    (준영속 상태의 특징 중 1가지는 식별자 값을 가집니다.)

3. 만약 1차 캐시에 엔티티가 없으면 DB에서 엔티티를 조회하고 1차캐시에 저장합니다.

4. 조회한 영속 엔티티(mergeMember)에 member엔티티의 값을 채워 넣습니다.

5. member엔티티의 모든 값을 mergeMember에 밀어 넣습니다. 이때 mergeMember의 "username1"이라는 이름을 "회원 명 변경"으로 바뀝니다.

6. mergeMember를 반환합니다.

 

병합이 끝나고 tx2.commit()을 호출하여 커밋했습니다.

mergeMember의 이름이 username1에서 회원 명 변경으로 변경되었으므로 변경 감지 기능이 동작해서 변경 내용이 DB에 반영됩니다.

 

준영속상태에 member엔티티에서 이름을 변경하였습니다.

merge()는 파라미터로 넘어온 준영속 엔티티를 사용해서 새롭게 병합된 영속상태의 엔티티를 반환합니다.

파라미터로 넘어온 엔티티는 병합 후에도 준영속 상태로 남아있습니다.

 


merge 정리

- 준영속 상태에서 엔티티의 값을 변경하였습니다.

- 준영속 상태의 엔티티를 merge()메소드에 파라미터로 전달합니다.

- 1차캐시에서 식별자 값으로 조회합니다. (준영속 상태이기때문에 캐시에서 조회된 결과가 없습니다.)

- 캐시에서 없으면 DB를 식별자 값으로 조회합니다.

- 조회된 결과를 1차 캐시에 저장합니다.

- 조회한 영속 엔티티와(mergeMember)와 준영속 엔티티(member)를 병합 합니다.

- 준영속엔티티를 영속엔티티에 밀어넣는 행위입니다. 이때 준영속상태에서 변경한 값이 영속 엔티티에도 적용됩니다.

- 변경된 영속 엔티티(mergeMember)를 리턴합니다.

- 커밋시 변경된 영속 엔티티가 DB에 저장됩니다.

 

 

 

 

'IT > JPA' 카테고리의 다른 글

영속성 관리 정리  (0) 2022.05.08
비영속 병합  (0) 2022.05.08
준영속 상태의 특징  (0) 2022.05.07
준영속 - detach, clear, close  (0) 2022.05.07
플러시 모드 옵션  (0) 2022.05.07