티스토리 뷰

JPA

JPA의 2가지 업데이트 방법

seungwonlee 2025. 9. 4. 19:03

JPA 프로젝트에서 update는 어떤 방식으로 하는 게 좋을까?

JPA 프로젝트를 하면서 가장 많이 쓰게 되는 기능 중 하나가 update입니다. 개발을 하다 "어떤 방식이 더 좋은 걸까" 하는 고민이 생겼습니다. 이글에서는 그 부분을 정리해보려고 합니다.

 

제가 고민하는 두 가지 방식

1. JPA의 장점인 Dirty Checking(변경 감지) 활용해서 엔티티의 필드를 직접 수정하는 방법

2. 새로운 객체를 만들어 교체하는 방법

 

두 가지 방법 모두 장단점이 있다고 GPT가 대답해 줍니다. 이번 글에서는 각각 어떤 특징이 있는지 그리고 실제로 언제 쓰면 좋을지 제 생각을 정리해 보겠습니다.

 

먼저 변경 감지를 활용해 필드를 직접 수정하는 방법입니다.

@Transactional
public void updateDepartment(Long departmentId, String name) {
    Department department = departmentRepository.findById(departmentId).orElseThrow(() -> new CoreException(ErrorType.DEPARTMENT_NOT_FOUND, departmentId));

    if (departmentRepository.findByName(name).isPresent()) {
        throw new CoreException(ErrorType.DEPARTMENT_ALREADY_EXISTS, name);
    }
    department.update(name);
}

// entity/Department.java
public void update(String name) {
    this.name = name;
}

DB에서 조회한 엔티티 객체의 상태를 변경하면 JPA가 변경을 감지하고 트랜잭션 종료될 때 자동으로 update를 실행해 DB에 반영합니다. save() 메서드를 별도로 호출할 필요 없이 코드가 간결하게 가능하고 JPA의 핵심 기능을 활용했습니다. 하지만 데이터 변경이 save() 호출 없이 마법처럼 일어나는 것처럼 보일 수 있습니다. 특히 복잡한 로직에서 변경 흐름을 추적하기 어려울 수 있습니다.

 

두 번째 방법인 새 객체 생성 후 저장 하는 방법입니다.

@Transactional
public void updateDepartment(Long departmentId, String name) {
    Department department = departmentRepository.findById(departmentId)
            .orElseThrow(() -> new CoreException(ErrorType.DEPARTMENT_NOT_FOUND, departmentId));
            
    if (departmentRepository.findByName(name).isPresent()) {
        throw new CoreException(ErrorType.DEPARTMENT_ALREADY_EXISTS, name);
    }
    
    Department changedDepartment = department.update(name);
    departmentRepository.save(changedDepartment);
}

// entity/Department.java
public Department update(String name) {
    return new Department(this.departmentId, name);
}

불변성을 지향하는 방식으로 update 할 데이터를 담은 새로운 엔티티 객체를 생성하고 save() 메서드를 명시적으로 호출하여 의도가 명확하고 직관적입니다. 하지만 새로운 객체를 매번 생성해야 하고 코드의 양이 변경 감지보다 약간 더 많아집니다.

 

고민과 결론 

  • 상황에 따라 다르게 적용하자

두 가지 방식의 장단점이 있기에 절대적으로 좋다고 단정 지을 수 없을 거 같습니다. 하지만 어떤 방식이 더 올바른 선택일지 고민했습니다. 그리고 과거에 잔액 충전, 사용 등 민감한 데이터를 다루는 는 기능을 개발했을 때 경험을 생각났습니다. 당시 저는 새 객체를 생성한 후 저장하는 방식을 선택했습니다. 그 이유는 잔액 데이터가 매우 중요하고 민감한 정보이고 단 하나의 오류도 허용해서는 안된다고 생각했기 때문입니다. 그래서 예측이 가능하고 명확해야 한다고 생각했습니다. 

 

JPA의 더티 체킹 방식은 코드가 간결하지만 잔액처럼 중요한 데이터의 변경이 마법처럼 일어나는 듯한 느낌을 줄 수 있습니다 반면 새로운 객체를 생성하고 명시적으로 save()를 호출하는 방식은 데이터 변경의 흐름을 투명하게 볼 수 있고 직관적이라고 생각됩니다. 

 

결론적으로 업데이트하려는 데이터의 성격에 따라 적절한 전략을 선택하는 것이 가장 현명하다고 생각됩니다. 일반적인 엔티티 부서명, 사용자 프로필 정보와 같은 일반적인 엔티티는 간결하고 생산성을 높일 수 있는 변경 감지를 사용하고 포인트, 재고, 잔액처럼 민감한 도메인 객체를 다를 때는 새로운 객체를 생성하고 명시적으로 저장하는 방식을 적용하는 것으로 제 생각을 정리하고 싶습니다.

 

728x90
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2025/10   »
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
글 보관함