티스토리 뷰

준영속 엔티티란?

 준영속 엔티티는 영속성 컨텍스트에서 관리하지 않는 엔티티이다. 이러한 준영속 엔티티를 수정하는 방법은 아래 예제를 통해서 알아보았다. 이렇게 준영속 엔티티가 생기는 경우는 등록 후 수정 화면에서 수정 폼을 전송할 때 객체를 통해서 전달 받게 되는데 해당 객체는 이미 DB에 저장 되었던 객체 또는 엔티티이며 식별자가 존재하게 된다. 그러나 영속성 컨텍스트에서는 관리하지 않는다. (단순히 컨트롤러를 통해 전달 받은 객체이기 때문)

 

1. 변경 감지 기능 사용

 준영속 엔티티는 관리하지 않는 엔티티이므로 이 엔티티의 식별자를 추출하여 이를 영속성 컨텍스트에서 관리하는 엔티티로 생성 후 변경 감지 기능을 사용하여 수정할 수 있도록 한다.

 

예제

 아래 예제의 주석은 웹 어플리케이션으로 가정하여 등록 후 수정 과정을 적었다.

 

Book.java

@Entity
public class Book {

    @Id
    @GeneratedValue
    private Long id;

    private String author;

    private String bookName;

    // getter,setter 생략
}

Main.java

// 엔티티 매니저 생략

// 등록 완료. 엔티티 저장.
System.out.println("등록 완료. 엔티티 저장.");
Book book1 = new Book();
book1.setBookName("JPA");
book1.setAuthor("tester");
em.persist(book1);
em.flush();
em.clear();

// 수정 폼 전송 후 생성한 객체. 준영속 엔티티(해당 엔티티 객체는 영속성 컨텍스트에서 관리하지 않는 객체이다.)
System.out.println("수정 폼 전송 후 생성한 객체. 준영속 엔티티(해당 엔티티 객체는 영속성 컨텍스트에서 관리하지 않는 객체이다.)");
Book book2 = new Book();
book2.setId(1L);
book2.setBookName("update_JPA");
book2.setAuthor("update_tester");

// 준영속 엔티티 -> 영속 엔티티 변경
System.out.println("준영속 엔티티 -> 영속 엔티티 변경");
Book findBook = em.find(Book.class, book2.getId());

// 영속 엔티티 변경 감지 기능으로 수정
System.out.println("영속 엔티티 변경 감지 기능으로 수정");
findBook.setBookName(book2.getBookName());
findBook.setAuthor(book2.getAuthor());
em.flush();
em.clear();

tx.commit();

실행 결과

등록 완료. 엔티티 저장. 
Hibernate: 
    select
        next value for Book_SEQ
Hibernate: 
    /* insert for
        jpabook.jpashop.domain.Book */insert 
    into
        Book (author, bookName, id) 
    values
        (?, ?, ?)
수정 폼 전송 후 생성한 객체. 준영속 엔티티(해당 엔티티 객체는 영속성 컨텍스트에서 관리하지 않는 객체이다.)
준영속 엔티티 -> 영속 엔티티 변경
Hibernate: 
    select
        b1_0.id,
        b1_0.author,
        b1_0.bookName 
    from
        Book b1_0 
    where
        b1_0.id=?
영속 엔티티 변경 감지 기능으로 수정
Hibernate: 
    /* update
        for jpabook.jpashop.domain.Book */update Book 
    set
        author=?,
        bookName=? 
    where
        id=?

 위의 실행 결과를 보면 준영속 엔티티의 식별자를 통해 엔티티를 조회하여 영속 엔티티를 새로 생성 후 변경 감지 기능인 set메서드를 통해 수정하였다.

 

2. merge(병합) 사용

 merge 메서드는 준영속 상태인 엔티티를 그대로 수정할 때 사용한다.

 

예제

Main.java

// 엔티티 매니저 생략

// 등록 완료. 엔티티 저장.
System.out.println("엔티티 저장. 등록 완료");
Book book1 = new Book();
book1.setBookName("JPA");
book1.setAuthor("tester");
em.persist(book1);
em.flush();
em.clear();

// 수정 폼 전송 후 생성한 객체. 준영속 엔티티(해당 엔티티 객체는 영속성 컨텍스트에서 관리하지 않는 객체이다.)
System.out.println("수정 후 폼 전송. 준영속 엔티티(해당 엔티티 객체는 영속성 컨텍스트에서 관리하지 않는 객체이다.)");
Book book2 = new Book();
book2.setId(1L);
book2.setBookName("update_JPA");
book2.setAuthor("update_tester");

// 준영속 엔티티를 merge 메서드를 통해 병합(수정)한다.
System.out.println("준영속 엔티티를 merge 메서드를 통해 병합(수정)한다.");
Book mergeBook = em.merge(book2);
System.out.println("update bookName: " + mergeBook.getBookName());
System.out.println("update author: " + mergeBook.getAuthor());

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

tx.commit();

실행 결과

엔티티 저장. 등록 완료
Hibernate: 
    select
        next value for Book_SEQ
Hibernate: 
    /* insert for
        jpabook.jpashop.domain.Book */insert 
    into
        Book (author, bookName, id) 
    values
        (?, ?, ?)
수정 후 폼 전송. 준영속 엔티티(해당 엔티티 객체는 영속성 컨텍스트에서 관리하지 않는 객체이다.)
Hibernate: 
    select
        b1_0.id,
        b1_0.author,
        b1_0.bookName 
    from
        Book b1_0 
    where
        b1_0.id=?
update bookName: update_JPA
update author: update_tester
Hibernate: 
    /* update
        for jpabook.jpashop.domain.Book */update Book 
    set
        author=?,
        bookName=? 
    where
        id=?

 위의 실행 결과를 보면 수정 후 폼 전송. 준영속 엔티티....의 출력된 콘솔 부분 다음에 select 문이 실행 된 것을 확인할 수 있다. 이는 준영속 엔티티를 .merge(book2)를 하면 JPA가 해당 준영속 엔티티의 식별자를 통해 DB를 조회 후 1차 캐시에 저장한다. 그리고 조회한 영속 엔티티(mergeBook)에 준영속 엔티티(book2)의 bookName과 author의 값을 조회한 영속 엔티티에 밀어 넣는다. (※book2를 merge해도 book2는 준영속 상태 그대로다. mergeBook과는 다른 객체이다.)

 

merge(병합) 사용시 주의할 점

 merge를 사용하면 단순할 수 있지만 치명적인 문제가 발생할 수 있다. 그것은 모든 속성 값을 변경한다는 것이다. 만약 author만 변경하는 폼이 있다면 author만 변경하면 되는데 만약 merge를 사용하게 되면 bookName도 같이 수정하게 된다. 이때 bookName은 값이 없으므로 null 값이 들어가게 된다.

 

예제

Main.java

// 위 과정 생략

// author만 수정
System.out.println("author만 수정");
Book book2 = new Book();
book2.setId(1L);
book2.setAuthor("update_tester");

// 준영속 엔티티를 merge 메서드를 통해 병합(수정)한다.
System.out.println("준영속 엔티티를 merge 메서드를 통해 병합(수정)한다.");
Book mergeBook = em.merge(book2);
System.out.println("update bookName: " + mergeBook.getBookName());
System.out.println("update author: " + mergeBook.getAuthor());

실행 결과

author만 수정
준영속 엔티티를 merge 메서드를 통해 병합(수정)한다.
Hibernate: 
    select
        b1_0.id,
        b1_0.author,
        b1_0.bookName 
    from
        Book b1_0 
    where
        b1_0.id=?
update bookName: null
update author: update_tester
Hibernate: 
    /* update
        for jpabook.jpashop.domain.Book */update Book 
    set
        author=?,
        bookName=? 
    where
        id=?

 위의 실행 결과를 보면 bookName도 같이 update문에 포함 된 것을 볼 수 있다. merge를 사용하면 위와 같은 문제가 발생할 수 있으니 조심해야한다.

 

정리

 준영속 엔티티를 수정하는 방법은 준영속 엔티티에서 식별자를 추출하여 영속 엔티티를 생성 후 해당 영속 엔티티를 변경 감지를 통해 수정하는 방법이 있고 또 하나는 준영속 엔티티를 merge를 통해 수정하는 방법이 있다. 하지만 merge는 엔티티 전체가 변경될 수 있으니 가급적 사용에 주의해야하며 최대한 변경 감지를 통해 수정하는 것이 안전하다.

 


본 포스팅은 “ 실전! 스프링 부트와 JPA 활용1 - 웹 애플리케이션 개발 편/인프런”를 학습한 내용을 정리한 것

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

<JPA> @Enumerated 사용 시 주의할 점  (0) 2024.10.31
<JPA> 벌크 연산시 주의할 점  (2) 2024.10.03
<JPA> 임베디드 타입이란?  (0) 2024.09.24
<JPA> 즉시 로딩과 지연 로딩이란?  (0) 2024.09.23
<JPA> @MappedSuperclass 이란?  (0) 2024.09.05
댓글
최근에 올라온 글
«   2026/03   »
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30 31
글 보관함
Total
Today
Yesterday