JPA는 초보자에게 쉬운 ORM처럼 보이지만, 실무에서는 오히려 더 많은 의문과 복잡함을 야기합니다. 본 글에서는 주니어 개발자들이 실무에서 자주 묻는 JPA 관련 질문들과, 팀장에게 "좋은 질문"을 던지는 방법까지 함께 소개합니다.
많은 주니어들이 오해하는 부분입니다. JPA는 객체지향적으로 DB를 다룰 수 있도록 도와주지만, 결국 RDB의 동작 원리와 SQL을 이해하고 있어야 문제를 해결할 수 있습니다.
@Entity
public class Member {
@Id
@GeneratedValue
private Long id;
private String name;
}
이렇게 간단히 모델링하더라도, JPA는 내부적으로 SQL을 만들어 실행합니다. 그 쿼리가 어떤 형태로 나가는지는 개발자가 이해하고 있어야 합니다.
지연 로딩은 JPA가 연관된 엔티티를 즉시 로딩하지 않고 실제로 접근할 때 쿼리를 실행하는 방식입니다. 이는 메모리 낭비를 줄이고, 초기 로딩 성능을 높이는 데 도움이 됩니다.
@ManyToOne(fetch = FetchType.LAZY)
private Team team;
위처럼 설정되면 member.getTeam()을 호출하기 전까지는 Team을 위한 쿼리가 실행되지 않습니다.
문제는? 실무에서는 해당 객체를 반복 조회할 때 N+1 문제가 발생하기 쉽습니다.
List<Member> members = memberRepository.findAll();
for (Member m : members) {
System.out.println(m.getTeam().getName());
}
→ 이 경우, SELECT가 1 + N번 실행되며 성능 이슈가 발생할 수 있습니다.
해결법: fetch join 또는 DTO 직접 조회 방식 활용
@Query("SELECT m FROM Member m JOIN FETCH m.team")
List<Member> findAllWithTeam();
네, 꼭 필요합니다. 트랜잭션은 데이터 일관성과 영속성 컨텍스트의 동작을 보장하기 위해 필수입니다.
예를 들어, 아래 코드에서 @Transactional이 없으면 setName을 해도 실제 DB에는 반영되지 않습니다.
@Transactional
public void updateName(Long id, String newName) {
Member member = memberRepository.findById(id).orElseThrow();
member.setName(newName); // dirty checking 발생
}
JPA는 트랜잭션이 활성화된 상태에서만 변경 감지(dirty checking)를 통해 자동 update 쿼리를 생성합니다. 트랜잭션 범위 외부에서는 flush가 발생하지 않아 DB에 아무 일도 일어나지 않습니다.
추가 예시:
@Transactional(readOnly = true)
public Member getMember(Long id) {
return memberRepository.findById(id).orElse(null);
}
readOnly 속성은 변경 감지를 비활성화하고 성능을 향상시키는 데 유용합니다.
대표적인 원인:
해결 방법:
JPA는 도메인 중심 설계에 적합하지만, SQL 위주 업무나 성능 튜닝이 중요한 상황에서는 MyBatis의 명시적 SQL이 선호될 수 있습니다. JPA는 러닝 커브가 높고 디버깅이 어려운 반면, MyBatis는 SQL을 직접 제어할 수 있다는 장점이 있습니다.
단순히 "이거 왜 안 돼요?"라고 묻는 질문은 정보가 부족해 답변하기 어렵습니다. 다음과 같이 배경 + 현재 시도 + 예상 결과를 포함해 질문하세요.
질문이 구체적일수록, 당신의 이해도와 태도가 함께 전달됩니다.
JPA는 단순히 써보는 것보다, 내부 동작과 쿼리 분석까지 이해할 때 비로소 "쓸 수 있게" 됩니다. 질문도 기술의 일부입니다. 좋은 질문이 좋은 개발자로 성장하는 길이라는 걸 기억하세요.
| 질문도 실력이다! 주니어 개발자를 위한 질문 꿀팁 (0) | 2025.06.19 |
|---|---|
| [입문 필독] Spring 계층 구조 예제와 자주 하는 실수 정리 (0) | 2025.06.12 |
| redis-cli 사용법 기초부터 실전까지: KEYS vs SCAN, 데이터 삭제까지 (2) | 2025.06.07 |
| 초보 백엔드 개발자를 위한 HTTP 상태코드 (0) | 2025.06.01 |
| Spring Boot에서 CORS 오류 완벽 해결하기 – @CrossOrigin, WebMvcConfigurer, 예외 처리까지 (0) | 2025.06.01 |