JPA 영속성 컨텍스트 - 수정

Daniel6364·2022년 8월 12일
0

엔티티 수정

SQL 수정 쿼리의 문제점

  • SQL을 사용하면 프로젝트가 커지고 요구사항이 늘어나면서 수정 쿼리도 점점 추가 된다.
  • 비즈니스 로직을 분석하기 위해 SQL을 계속 확인해야한다.
  • 직/간접적으로 비즈니스 로직이 SQL에 의존하게 된다.

변경 감지

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(member) 이런 코드가 있어야 하지 않을까?

trnasaction.commit(); // 트랜잭션 커밋

JPA로 엔티티를 수정할 떄는 단순히 엔티티를 조회해서 데이터만 변경하면 된다. 엔티티의 데이터만 변경하면 변경사항을 데이터베이스에 자동으로 반영하는 기능인 변경감지(dirty checking)에 의해 자동으로 반영된다.

JPA는 엔티티를 영속성 컨텍스트에 보관할 때, 최초 상태를 복사해서 저장해두는데 이것을 스냅샷이라 한다. 그리고 플러시 시점에 스냅샷과 엔티티를 비교해서 변경된 엔티티를 찾는다.

  1. 트랜잭션을 커밋하면 엔티티 매니저 내부에서 먼저 플러시(flush())가 호출 된다.
  2. 엔티티와 스냅샷을 비교해서 변경된 엔티티를 찾는다.
  3. 변경된 엔티티가 있으면 수정 쿼리를 생성해서 쓰기 지연 SQL저장소에 보낸다.
  4. 쓰기 지연 저장소의 SQL을 데이터베이스에 보낸다.
  5. 데이터베이스 트랜잭션을 커밋한다.

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

변경 감지로 인해 실행된 UPDATE SQL을 살펴보자

UPDATE MEMBER
SET 
	NAME=?,
    AGE=?
WHERE
	ID=?

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

UPDATE MEMBER
SET 
	NAME=?,
    AGE=?
    GRADE=?,
    ...
WHERE
	ID=?

이렇게 모든 필드를 사용하면 데이터베이스에 보내는 데이터 전송량이 증가하는 단점이 있지만, 다음과 같은 장점으로 인해 모든 필드를 업데이트한다.

  • 모든 필드를 사용하면 수정 쿼리가 항상 같다 -> 재사용
  • 데이터베이스에 동일한 쿼리를 보내면 데이터베이스는 이전에 한 번 파싱된 쿼리를 재사용할 수 있다.

필드가 많거나 저장되는 내용이 너무 크면 수정된 데이터만 사용해서 동적으로 UPDATE SQL을 생성하는 전략인 하이버네이트 확장 기능을 사용하면 된다.

@Entity
@org.hibernate.annotations.DynamicUpdate
@Table(name = 'Member")
public class Member {...}

@org.hibernate.annotations.DynamicUpdate 를 사용하면 수정된 데이터만 사용해서 동적으로 UPDATE SQL을 생성한다.

컬럼이 대략 30개 이상이 되면 기본 방법인 정적 수정 쿼리보다 @DynamicUpdate를 사용한 동적 수정 쿼리가 빠르다고 한다. 하지만 한 테이블에 컬럼이 30개 이상 된다는 것은 설계상 적절한지 확인이 필요하지 않을까?

profile
The Office Lover

0개의 댓글