백엔드에서 닉네임 중복 오류를 고치던 중 갑자기 잘 동작하던 UserRepository 에 있는 점수를 내림차순으로 정렬하여 조회하는 findAllByOrderByScoreDesc() 메소드에서 오류발생
No default constructor for entity: : backend.csquiz.entity.User; nested exception is org.hibernate.InstantiationException
package backend.csquiz.repository;
import backend.csquiz.entity.User;
import java.util.List;
import org.springframework.data.jpa.repository.JpaRepository;
import java.util.Optional;
public interface UserRepository extends JpaRepository<User, Long> {
Optional<User> findByNickname(String nickname); // 닉네임으로 사용자 조회
// 점수 내림차순으로 정렬하여 모든 사용자 조회
List<User> findAllByOrderByScoreDesc();
}
findAllByOrderByScoreDesc() 메소드 역할UserRepository 인터페이스에서 findAllByOrderByScoreDesc()는 사용자 목록을 score 기준으로 내림차순 정렬하여 조회하는 메소드이다.SELECT u FROM User u ORDER BY u.score DESC 와 같은 JPQL이 실행된다.User)는 반드시 기본 생성자(no-args constructor)를 가져야 한다.<aside> 💡
“기본 생성자가 없으면 왜 안될까?”
JPA는 엔티티 객체를 데이터베이스에서 조회할 때 내부적으로 리플렉션(Reflection) 을 사용하여 객체를 생성한다. 이 과정에서는 new 키워드와 같은 일반적인 생성자 호출 방식이 아니라, 기본 생성자(no-args constructor)를 통해 객체를 먼저 생성한 뒤, 필드에 값을 주입하는 방식으로 동작하게 된다.
즉, JPA는 다음과 같은 순서를 따르게 된다:
User user = new User(); 와 유사한 방식으로 객체를 메모리에 생성user.setNickname(...), user.setScore(...) 등의 방식)따라서, 기본 생성자가 없으면 객체를 생성할 수 없어 오류가 발생하게된다.
이는 Hibernate나 Spring Data JPA에서 다음과 같은 예외로 나타날 수 있다:
No default constructor for entity: : backend.csquiz.entity.User;
nested exception is org.hibernate.InstantiationException
</aside>
기존 UserService에서 사용자 점수를 저장하는 방식은 다음과 같았다.
// 사용자 점수 저장
@Transactional
public void saveScore(String nickname, int score) {
User user = userRepository.findByNickname(nickname)
.orElseGet(() -> {
User newUser = new User(nickname, score);
return userRepository.save(newUser);
});
// 점수 누적
user.setScore(user.getScore() + score);
userRepository.save(user);
}
만약 사용자가 존재하지 않을 경우, 생성자를 이용해 새로운 사용자를 생성한 뒤 저장하는 방식이었다.