728x90
반응형
SMALL
JPA를 사용하다 보면 같은 조건으로 조회하는데도 반환 타입에 따라 동작 방식이 달라지는 경우가 있습니다.
특히 List, 단일 엔티티 반환(Member), 그리고 Optional<Member> 는 반환 결과가 완전히 다르기 때문에 정확히 이해하고 사용하는 것이 중요합니다.
이번 글에서는 반환 타입의 차이를 코드와 함께 정리해보겠습니다.
✔️ 1. 테스트 코드로 살펴보는 반환 결과
@Test
public void returnType(){
Member m1 = new Member("AAA", 10);
Member m2 = new Member("AAA", 20);
memberRepository.save(m1);
memberRepository.save(m2);
List<Member> aaa = memberRepository.findListByUsername("AAA");
Member bbb = memberRepository.findMemberByUsername("BBB");
System.out.println("bbb : "+bbb);
Optional<Member> ccc = memberRepository.findOptionalByUsername("AAA");
System.out.println("ccc : "+ccc);
List<Member> ddd = memberRepository.findListByUsername("asdf");
System.out.println("ddd : "+ddd.size());
Member eee = memberRepository.findMemberByUsername("asdf");
System.out.println("eee : "+eee);
Optional<Member> fff = memberRepository.findOptionalByUsername("asdf");
System.out.println("fff : "+fff);
}
그리고 Repository 인터페이스는 다음과 같습니다.
List<Member> findListByUsername(String username);
Member findMemberByUsername(String username);
Optional<Member> findOptionalByUsername(String username);
각 타입의 차이를 하나씩 살펴보겠습니다.
✔️ 2. List<Member> — 결과가 없어도 null을 반환하지 않는다
List<Member> list = memberRepository.findListByUsername("asdf");
- 조회 결과가 없으면 null 이 아닌 빈 리스트([])를 반환
- size() = 0
- NPE 걱정을 하지 않아도 됨 → 가장 안전한 방식
특징 요약
| 상황 | 반환값 |
| 결과 없음 | [] |
| 결과 여러 개 | [Member, Member, ...] |
JPA는 컬렉션 타입을 반환할 때 절대 null을 반환하지 않습니다.
✔️ 3. Member — 단일 엔티티 반환, 결과 없으면 null
Member member = memberRepository.findMemberByUsername("asdf");
- 조회 결과가 없으면 null 반환
- 조회 결과가 2개 이상이면 NonUniqueResultException 발생
특징 요약
| 상황 | 반환값 |
| 결과 없음 | null |
| 결과 1개 | Member |
| 결과 여러 개 | ❌ 예외 발생 |
단일 조회에서는 사용하는 순간 항상 null 체크가 필요합니다.
✔️ 4. Optional<Member> — 결과 없으면 Optional.empty
Optional<Member> member = memberRepository.findOptionalByUsername("asdf");
- 결과가 없으면 Optional.empty
- 단일 데이터 조회를 안전하게 감싸는 방식
- 단일 결과가 2개 이상이면 역시 예외 발생 (NonUniqueResultException)
특징 요약
| 상황 | 반환값 |
| 결과 없음 | Optional.empty |
| 결과 1개 | Optional<Member> |
| 결과 여러 개 | ❌ 예외 발생 |
최근에는 단일 조회 시 Optional을 기본으로 쓰는 것이 안전한 패턴입니다.
✔️ 5. 반환 타입 비교 정리
| 반환 타입 | 결과 없음 | 결과 하나 | 결과 여러 개 | 비고 |
| List<T> | 빈 리스트([]) | 리스트 | 리스트 | 가장 안전 |
| T | null | 엔티티 | ❌ NonUniqueResultException | null 체크 필요 |
| Optional<T> | Optional.empty | Optional.of(entity) | ❌ NonUniqueResultException | 추천 방식 |
✔️ 6. 실제 추천 패턴
🔹 컬렉션 조회
→ 무조건 List
List<Member> members = repo.findListByUsername("AAA");
🔹 단건 조회
→ Optional 사용 권장
Optional<Member> member = repo.findOptionalByUsername("AAA");
🔹 단건 + 최적화된 비즈니스 규칙이 있는 경우
null 허용 가능하면 단일 객체 반환도 OK
Member member = repo.findMemberByUsername("AAA");
하지만 예외 상황 처리를 명확히 해야 합니다.
✔️ 7. 정리
Spring Data JPA의 반환 타입은 단순한 문법 문제가 아니라 비즈니스 규칙과 오류 처리 방식에 직접적으로 영향을 줍니다.
- "없다면 빈 리스트" → List
- "단건 조회인데 null-safe 하게 받고 싶다" → Optional
- "정확히 한 건이어야 한다" → 단일 엔티티 + 예외 처리
명확한 기준을 잡고 사용하면 코드 안정성이 훨씬 높아집니다!
728x90
반응형
LIST
'개발지식 > Backend Engineering' 카테고리의 다른 글
| 비동기 처리란 무엇인가?(MQ / Kafka) (0) | 2026.01.23 |
|---|---|
| 전략 패턴 + AOP로 정책 로직을 분리한 설계 (0) | 2025.12.28 |
| 📚 Spring Data JPA Repository 제대로 써보기 (0) | 2025.11.12 |
| Kotlin 기본 구조(예시 코드) (8) | 2025.08.14 |
| Kotlin 기본 함수(예시 코드) (7) | 2025.08.12 |