Project/Greendar

처음으로 회원가입시 생기는 문제

sung.hyun.1204 2023. 4. 21. 16:09

데이터베이스의 멤버가 아무도 없는 상태에서 회원가입을 하려다 에러가 생기는 것을 찾았다.

 

다음 에러를 만나면 데이터 베이스 부터 한번 보자,  데이터가 있는지

javax.persistence.NoResultException: No entity found for query

 

 

분석 : 

기존에는 회원 가입을 할시 다음과 같은 코드를 거친다.

 

Repo 단의 saveMember code 이다.

 

Service layer 에서 validateDuplicateEmail 즉 이메일을 중복 처리하는 로직을 두고 saveMember 를 최대한 member 만 생성하는 함수로 변경을 해는것 좋아보인다. 에러를 잡고 테스트코드 짜고 리펙을 해주자.

 

public Optional<Member> saveMember(String name, String password, String email, String imageUrl, String message, String token) {
        try {
            validateDuplicateEmail(email);
            Member member = Member.of(name, password, email, imageUrl, message, token);
            em.persist(member);
            return Optional.of(member);
        } catch (NoResultException e) {
            return Optional.empty();
        }
    }

validateDuplicateEmail :  saveMember 에서 문제가 생기는 부분이다.

private void validateDuplicateEmail(String email){
    findOneByEmail(email).ifPresent( m -> {
        throw new IllegalStateException("이미 존재하는 이메일 입니다.");
    });
}

 

 

Member 에서만 사용되는 것이 아닌 다른 서비스 레이어세도 호출 중인 findOnebyEmail 이다.

public Optional<Member> findOneByEmail(String userEmail) {
    Member member = em.createQuery("select m from Member m " +
                            "where m.email = :email"
                    , Member.class)
            .setParameter("email", userEmail)
            .getSingleResult();
    return Optional.ofNullable(member);
}

 

위의 코드들은 유저가 아무도 없는 첫 시점에서 이메일을 확인할 사항이 없어서 에러가 난다,,

 

이유 :

getSingleResult()  의  경우 쿼리 결과가 없는 경우 NoResultExecption , 여러 개의 결과가 있는 경우는 NonUniqueResultException을 던진다.     즉 , 가능하면 하나이상의 결과가 보장된 상태에서 중복되는 값이 없는 경우 사용하는것이 정확하다. 

 

하단의 코드처럼 다음 부분을 바꿔주자.

 

getSingleResult()  ->     " .getResultList().stream().findFirst().orElse(null); "

 

주어진 값의 첫번째 값을 반황하거나 없으면 null 을 반환한다.

 

 

public Optional<Member> saveMember(String name, String password, String email, String imageUrl, String message, String token) {
    try {
        validateDuplicateEmail(email);
        Member member = Member.of(name, password, email, imageUrl, message, token);
        em.persist(member);
        return Optional.of(member);
    } catch (IllegalStateException e) {
        return Optional.empty();
    }
}
public Optional<Member> findOneByEmail(String userEmail) {
    Member member = em.createQuery("select m from Member m " +
                            "where m.email = :email"
                    , Member.class)
            .setParameter("email", userEmail)
            .getResultList()
            .stream()
            .findFirst()
            .orElse(null);
    return Optional.ofNullable(member);
}
private void validateDuplicateEmail(String email){
    findOneByEmail(email).ifPresent( m -> {
        throw new IllegalStateException("이미 존재하는 이메일 입니다.");
    });
}

 

 

요약 :   

기술을 알고 쓰는것이 중요하다. 

아는것이 많아야 에러를 빠르게 잡느것을 알았다.

 

팀원이 지금의 코드를 이해를 하게 되면 다음 편에서는 data JPA 를 이용한 리펙토링 관련 포스팅을 올릴거다.