
JPA를 사용하는 프로젝트에서 클레스 레벨에 @Setter 어노테이션을 사용하는 것은 영속성 컨텍스트 (Persistence Context) 의 동작 방식과 변경 감지 (Dirty Checking) 메커니즘을 이해할 때 문제를 야기할 수 있다.
영속성 컨텍스트는 JPA가 엔티티의 생명 주기를 관리하고, 동일성 (Identity)을 보장하며, 쓰기 지연, 변경 감지 기능을 제공하는 핵심 공간이다.
쉽게 말하면 DB와 엔티티 코드를 연결하는 다리 역할을 한다고 할 수 있다.
이 중, 변경 감지 (Dirty Checking) 는 영속성 컨텍스트의 핵심 기능이다.
엔티티가 JPA에 의해 관리되는 영속 상태 (Persist State) 일 때, 엔티티 객체의 상태 변화를 감지하고, 트랜잭션 커밋 시점에 변경된 내용을 모아서 한 번에 SQL 쿼리(update)를 날린다.
member.setName("홍길동");
위와 같이 setter로 엔티티의 값을 바꾸면 JPA는 다음 처럼 동작한다.
name 필드가 바뀌었으니 트랜젝션 끝나면 DB에도 쿼리를 날려야겠다!
update member
set name = '홍길동'
where id = 1
위와 같이 update 쿼리가 자동으로 발생한다.
이처럼 JPA 변경 감지 기능을 통해 자동으로 쿼리를 발생시키는 경우 다음과 같은 문제가 발생할 수 있다.
@Setter로 발생 된 쿼리는 "누가", "왜" 값을 변경했는지에 대한 의도를 알 수 없다.
개발자가 의도하지 않은 쿼리가 발생하여 데이터베이스로 전송될 수 있다.
엔티티의 변경 지점(메서드)을 명확하게 하지 않으면, 유지보수성이 떨어지고 새로운 사항에 대해 확장성이 떨어질 수 있다.
클래스 레벨의 @Setter 사용을 지양하고, 변경 의도를 담은 메서드를 엔티티 내에 직접 작성한다!
public void changeName(String newName) {
if (newName == null || newName.trim().isEmpty()) {
throw new IllegalArgumentException("이름은 비어있을 수 없습니다.");
}
this.name = newName;
}
위와 같이 데이터 변경 역할을 하는 메서드를 명시한다.