인프런 영문 브랜드 로고
인프런 영문 브랜드 로고

인프런 커뮤니티 질문&답변

종운님의 프로필 이미지
종운

작성한 질문수

자바 ORM 표준 JPA 프로그래밍 - 기본편

DirtyChecking 질문입니다!

작성

·

215

0

회원을 수정하고, 회원의 닉네임이 중복되는 경우를 검증하고 싶었습니다. 더티체킹은 트랜잭션이 종료됐을 때 영속성 컨텍스트에서 변경된 것이 있는지 확인하고 변경된 것을 확인되면 업데이트 되는 것으로 알고 있는데요.

@Transactional
public void update(Long id, String name) {
    Member member = findOne(id);
    member.setName(name);

    validateDuplicateMember(member);
}

private void validateDuplicateMember(Member member) {
    // NullPointerException 발생 X
    List<Member> findMembers = memberRepository.findByName(member.getName());

    if (!findMembers.isEmpty()) {
        throw new IllegalStateException("이미 존재하는 회원입니다.");
    }
}

제가 의도한 목적은 다음과 같습니다.

  1. 회원을 조회 -> 영속성 컨텍스트 영속상태

  2. 회원 객체에 대한 이름을 변경 -> 트랜잭션 종료 시 더티체킹 예상

  3. 현재 객체 전달

  4. 전달 된 회원의 이름을 가진 회원을 조회

  5. 중복 시 Rollback, 아니라면 commit 후 더티체킹 이후 회원 엔티티 수정

하지만 중복이 아님에도 중복 예외가 발생하길래 log를 확인해본 결과

List<Member> findMembers = memberRepository.findByName(member.getName());

를 수행하기 전에 flush()가 되는 부분을 확인 할 수 있었습니다.

의심되는 부분은 4번에서 회원을 조회하는 과정에서 쿼리를 수행해야해서, 그 과정에서 쓰기 지연 저장소에 있던 쿼리들이 flush() 된 것이 아닌가 하는 의심이 듭니다.

그럼 제가 원하는 목적을 수행하기 위해서는 메서드를 아래와 같이 변경해야만 하는지..

@Transactional
public void update(Long id, String name) {
    validateDuplicateMember(name);

    Member member = findOne(id);
    member.setName(name);
}

private void validateDuplicateMember(String name) {
    // NullPointerException 발생 X
    List<Member> findMembers = memberRepository.findByName(name);

    if (!findMembers.isEmpty()) {
        throw new IllegalStateException("이미 존재하는 회원입니다.");
    }
}

다른 질문에서 중복 검증 시 영한님의 다음과 같은 답변을 확인 할 수 있었는데요.

@Transactional
public void update(Long id, String name) {
    Member member = findOne(id);
    validateDuplicateMember(member);
    member.setName(name);
}

private void validateDuplicateMember(Member member) {
    // NullPointerException 발생 X
    List<Member> findMembers = memberRepository.findByName(member.getName());

    if (!findMembers.isEmpty()) {
        throw new IllegalStateException("이미 존재하는 회원입니다.");
    }
}

이 부분은 변경되기 전이고 이미 등록된 상태의 Member를 가져오는 것이기 때문에 회원 이름 수정 시 중복 가능성에 대한 예외를 검증하는 것이 아니지 않나 하는 생각이 들어서 질문드립니다..!

답변 1

1

안녕하세요, 종운 님! 공식 서포터즈 codesweaver 입니다.

JPA는 데이터베이스와 동기화 하는 포인트가 여럿 있는데요, 하나는 아시다시피 트랜잭션이 커밋되었을 때고 하나는 JPQL이 실행되기 전입니다. findByName()은 엔터티의 키를 이용한 검색이 아니기에 JPQL을 사용하는데 이 때 강제로 flush()가 발생합니다.

 

아래 첨부해주신 코드가 강의 코드 그대로라면.. 말씀하신것처럼 변경하려는 값에 대한 유효성 검증이 아닙니다...!! :)

감사합니다.

종운님의 프로필 이미지
종운
질문자

감사합니다! 주 식별자가 아닌 컬럼으로 조회를 하게 되면 영속성 컨텍스트를 사용하지 않고 jpql이 사용된다는 부분도 얻어갈 수 있었네요! 이해되었습니다!

종운님의 프로필 이미지
종운

작성한 질문수

질문하기