작성
·
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("이미 존재하는 회원입니다.");
}
}
제가 의도한 목적은 다음과 같습니다.
회원을 조회 -> 영속성 컨텍스트 영속상태
회원 객체에 대한 이름을 변경 -> 트랜잭션 종료 시 더티체킹 예상
현재 객체 전달
전달 된 회원의 이름을 가진 회원을 조회
중복 시 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이 사용된다는 부분도 얻어갈 수 있었네요! 이해되었습니다!