• 카테고리

    질문 & 답변
  • 세부 분야

    백엔드

  • 해결 여부

    미해결

DirtyChecking 질문입니다!

23.05.08 13:44 작성 조회수 162

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님의 프로필

codesweaver

2023.05.10

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

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

 

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

감사합니다.

종운님의 프로필

종운

질문자

2023.05.11

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