티스토리 뷰

안녕하세요. 오늘은 JPA(Java Persistence API) 의 핵심 기능 중 하나인 더티 체킹(Dirty Checking) 에 대해 간단한 예제를 통해 알아보겠습니다. JPA 를 사용하다 보면 엔티티의 변경 사항이 자동으로 데이터베이스에 반영되는 경우가 있습니다. 그것이 바로 더티 체킹입니다. 이번 포스팅에서는 더티 체킹의 개념, JPA 의 영속성 컨텍스트, 그리고 간단한 예제를 통해 더티 체킹의 동작 방식에 대해 알아보겠습니다.


1. 더티 체킹이란?

더티 체킹은 JPA가 영속 상태의 엔티티 객체의 변경 사항을 자동으로 감지하여 데이터베이스에 반영하는 메커니즘입니다. 개발자가 명시적으로 UPDATE 쿼리를 작성하지 않아도, 엔티티의 필드 값을 변경하면 JPA가 이를 감지해 트랜잭션 커밋 시 자동으로 업데이트 쿼리를 실행합니다.

 

1.1. 더티 체킹의 핵심

  • 영속성 컨텍스트(Persistence Context): JPA가 엔티티를 관리하는 공간으로, 더티 체킹은 이 컨텍스트 안에서 동작합니다.
  • 스냅샷 비교: 엔티티가 영속 상태로 들어갈 때 JPA는 해당 엔티티의 스냅샷(초기상태)을 저장합니다. 트랜잭션 커밋 시 현재 상태와 스냅샷을 비교하여 변경된 필드를 감지합니다.
  • 자동업데이트: 변경이 감지되면 JPA가 자동으로 UPDATE 쿼리를 생성해 데이터베이스에 반영합니다.

 

1.2. 사용처

  • 엔티티의 특정 필드를 변경하고, 이를 즉시 데이터베이스에 반영하고 싶을 때
  • 수동으로 UPDATE 쿼리를 작성하지 않고, 객체 지향적으로 엔티티만 수정해도 DB가 동기화되길 원할때

2. JPA의 영속성

JPA의 더티 체킹을 이해하려면 영속성 컨텍스트엔티티의 생명주기를 알아야 합니다. 영속성 컨텍스트는 JPA가 엔티티를 관리하는 메모리 공간으로, 엔티티의 상태를 추적하고 데이터베이스와 동기화합니다.

 

2.1. 엔티티의 상태

  • 비영속(Transient): 엔티티 객체가 생성되었지만, 영속성 컨텍스트에 관리되지 않는 상태(new 로 생성한 객체)
  • 영속(Managed): 엔티티가 persist 또는 find 를 통해 영속성 컨텍스트에 추가된 상태. 이 상태에서 더티 체킹이 동작합니다.
  • 준영속(Detached): 영속성 컨텍스트에서 분리된 상태
  • 삭제(Removed): 엔티티가 삭제 예정 상태로, 커밋 시 DELETE 쿼리 실행

 

2.2. 영속성 컨텍스트의 역할

  • 1차 캐시: 엔티티를 저장하여 동일 트랜잭션 내에서 재사용
  • 스냅샷 관리: 엔티티의 초기 상태를 저장해 더티 체킹에 활용
  • 지연 쓰기(Write-Behind): 트랜잭션 커밋 시 변경 사항을 한꺼번에 DB에 반영
  • 동일성 보장: 동일 엔티티에 대해 동일한 객체 참조 제공

※더티 체킹은 영속 상태에서만 동작하므로, save 또는 find 로 엔티티를 영속성 컨텍스트에 추가해야 합니다.


3. 예제

이제 간단한 예제를 통해 더티 체킹이 어떻게 동작하는지 살펴보겠습니다. 사용자 관리 시스템에서 User 엔티티를 조회하고, 이름과 이메을 변경하는 시나리오를 구현했습니다.

예제 시나리오

  • 사용자 조회: User 엔티티를 ID로 조회하여 영속 상태로 만듦
  • 정보 수정: 사용자의 이름과 이메일을 변경
  • 더티 체킹: 변경된 필드가 트랜잭션 커밋 시 자동으로 데이터베이스에 반영

 

User 엔티티

import jakarta.persistence.*;
import lombok.*;

@Entity
@Getter
@Builder(toBuilder = true)			    // Builder 패턴 지원(복사)
@NoArgsConstructor(access = AccessLevel.PROTECTED)  // 외부 직접 호출 방지
@AllArgsConstructor(access = AccessLevel.PRIVATE)   // 생성자 비공개: Builder 로만 생성 유도
@Table(name = "users")
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column(name = "name")
    private String name;

    @Column(name = "email")
    private String email;
    
    private void setName(String name){
    	this.name = name;
    }
    
    private void setEmail(String email){
    	this.email = email;
    }
}

 

UserService

import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Service
@RequiredArgsConstructor
public class UserService {
    private final UserRepository userRepository;

    @Transactional
    public void updateUser(Long userId, String newName, String newEmail) {
        // 사용자 조회 (영속 상태)
        User user = userRepository.findById(userId)
            .orElseThrow(() -> new IllegalArgumentException("User not found"));

        // 필드 변경
        user.setName(newName);
        user.setEmail(newEmail);

        // 더티 체킹으로 변경 사항 자동 반영
        // 명시적 save() 호출 불필요
    }

    @Transactional
    public void createUser(String name, String email) {
        // 사용자 생성 및 저장
        User user = User.builder()
            .name(name)
            .email(email)
            .build();
        userRepository.save(user);

        // 추가 변경 (영속 상태에서)
        user.setName(name + "_updated");

        // 더티 체킹으로 변경 사항 자동 반영
    }
}

 

UserRepository

import org.springframework.data.jpa.repository.JpaRepository;

public interface UserRepository extends JpaRepository<User, Long> {
}

 

동작 설명

  1. 사용자 생성
    • User 객체를 생성하고 save 로 영속 상태로 만듦
    • setName 으로 이름을 변경하면 더티 체킹이 이를 감지
    • 트랜잭션 커밋 시 INSERT UPDATE 쿼리 실행
  2. 사용자 수정
    • findByIdUser 를 조회하여 영속 상태로 만듦
    • setName setEmail 로 필드 변경
    • 트랜잭션 커밋 시 더티 체킹이 변경을 감지해 UPDATE 쿼리 실행

4. 마무리

JPA의 더티 체킹은 엔티티의 변경 사항을 자동으로 데이터베이스에 반영하는 강력한 기능입니다. 영속성 컨텍스트를 통해 스냅샷을 비교하며, 개발자가 SQL 쿼리를 직접 작성하지 않고도 객체 지향적으로 데이터를 관리할 수 있게 해줍니다. 이번 포스팅에서는 더티 체킹의 개념, 영속성 컨텍스트, 그리고 간단한 사용자 관리 예제를 통해 동작 방식을 살펴보았습니다.

  • 영속 상태 유지: save 또는 find 로 엔티티를 영속성 컨텍스트에 추가
  • 트랜잭션 필수: 더티 체킹은 @Transactional 안에서 동작
  • 성능 주의: 대량 데이터 처리 시에는 더티 체킹 대신 벌크 연산 고려

감사합니다.

최근에 올라온 글
Total
Today
Yesterday