ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [JPA] JPA의 변경감지에 대해서
    데이터베이스 2022. 7. 11. 11:16

    변경감지란?

    트랜잭션이 커밋되는 시점에 엔티티의 변경사항이 있으면 UPDATE 쿼리를 자동으로 생성해서

    데이터베이스에 반영하는 JPA의 기능

     

     

            EntityManager em = emf.createEntityManager();
            EntityTransaction transaction = em.getTransaction();
            transaction.begin();
    
            // 영속 엔티티 조회
            Member memberA = em.find(Member.class, "memberA");
    
            // 영속 엔티티 데이터 수정
            memberA.setUsername("hi");
            memberA.setAge(10);
    
            //em.update(memberA) 이런 코드가 있어야 하지 않을까?
    
            transaction.commit();

    JPA의 엔티티매니저는 update라는 메서드를 제공하지 않는다. 그렇다면 JPA 환경에서 엔티티를 수정할 때는

    어떤 방법이 있을까?

     

    변경하고 싶은 엔티티를 조회해서 해당 엔티티의 데이터를 변경하면 

    트랜잭션 커밋 시점에 엔티티의 변경사항을 감지해서 자동으로 데이터베이스에 반영해준다.

     

     

     


     

    변경감지가 일어나는 과정

    JPA는 엔티티를 영속성 컨텍스트에 보관할 때, 최초 상태를 복사해서 저장해두는데 이것을 스냅샷이라고 한다.

    그래서 엔티티매니저를 flush 하는 시점에 스냅샷과 엔티티를 비교해서 변경된 엔티티를 찾는다.

     

    변경감지 흐름

    1. 트랜잭션을 커밋하면 엔티티매니저 내부에서 먼저 플러시(flush())가 호출된다.

    2. 엔티티의 스냅샷을 비교해서 변경된 엔티티를 찾는다.

    3. 변경된 엔티티가 있으면 수정 쿼리를 생성해서 쓰기 지연 SQL 저장소에 보낸다.

    4. 쓰기 지연 저장소의 SQL을 데이터베이스에 보낸다.

    5. 데이터베이스 트랜잭션을 커밋한다.

     

    변경감지는 영속성 컨텍스트가 관리하는 영속 상태의 엔티티에만 적용된다.
    비영속, 준영속 상태의 엔티티는 데이터 값을 변경해도 데이터베이스에 반영되지 않음

     

     


     

    JPA가 생성하는 UPDATE 쿼리문

    엔티티의 변경사항이 생겼을 때 JPA가 생성하는 쿼리문은 어떻게 생겼을까

     

    우리가 예상하는 쿼리문

     

     

    실제 쿼리문

     

    회원의 이름만 수정했으니 실제로 이름부분은 수정하는 쿼리문이 생성될것이라 예상하지만

    JPA의 기본 전략은 엔티티의 모든 필드를 업데이트한다.

     

    이렇게 모든 필드를 사용하면 데이터베이스에 보내는 데이터 전송량이 증가하는 단점이 있지만

    다음과 같은 장점으로 인해 모든 필드를 업데이트한다.

     

    장점

    • 모든 필드를 사용하면 수정 쿼리가 항상 같다.(바인딩 되는 데이터는 다름)  따라서
      어플리케이션 로딩 시점에 수정쿼리를 미리 생성해두고 재사용할 수 있다.
    • 데이터베이스에 동일한 쿼리를 보내면 데이터베이스는 이전에 한 번 파싱된 쿼리를 재사용할 수 있다.

     

     

     

     

    테이블의 컬럼이 너무 많아서 부담이 된다면 하이버네이트의 확장 기능을 사용하면 된다.

    @org.hibernate.annotations.DynamicUpdate
    @Entity
    public class Member { ... }

    org.hibernate.annotations.DynamicUpdate 애노테이션을 사용하면 UPDATE 쿼리를 생성할 때

    수정된 쿼리문 골라서 넣어준다. 참고로 데이터를 저장할 때 데이터가 null이 아닌 필드만 INSERT SQL에

    동적으로 넣어주는 @DynamicInsert 애노테이션도 있다.

     

    상황에 따라 다르지만 컬럼이 대략 30개 이상이 되면 기본 방법인 정적 수정 쿼리보다 @DynamicUpdat를 사용한

    동적 수정 쿼리가 더 빠르다고 한다. 

     

     

    출처 : 자바 ORM 표준 JPA 프로그래맹(김영한)

     

Designed by Tistory.