Notice
Recent Posts
Recent Comments
Link
enginner_s2eojeong
<실전! 스프링 부트와 JPA 활용1 - 웹 애플리케이션 개발> 1편 본문
<목차>
1. 들어가기 전 - 용어 정리
2. 도메인 분석 설계
3. 애플리케이션 구현 준비
작년 하반기에 스프링부트 스터디를 진행하며 노션에 정리해놓았던 내용들입니다.
최근 연합 프로젝트를 진행하면서 당시 공부한 내용을 실제로 적용해볼 수 있었고 덕분에 JPA와 스프링 부트에 대한 개념을 더욱 확실히 다질 수 있었습니다. 이번에는 그 경험을 복습할 겸 좀 더 다듬고 정리된 형태로 블로그에도 공유해보려 합니다.
1. 들어가기 전 - 용어 정리
@Repository
public class MemberRepository {
@PersistenceContext
private EntityManager em;
public Long save(Member member){
em.persist(member);
return member.getId();
}
public Member find(Long id){
return em.find(Member.class, id);
}
}
@Repository
- 해당 클래스가 데이터 접근을 처리하는 repository 클래스 임을 나타냄.
- repository는 데이터베이스와의 직접적인 상호작용을 캡슐화하여 애플리케이션의 다른 부분이 데이터베이스의 복잡한 동작을 신경 쓰지 않도록 함.
- 예를 들어, CRUD (Create, Read, Update, Delete) 작업을 repository 계층에서 수행하고, 서비스 계층이나 비즈니스 로직에서는 이를 호출만 하면 됨.
@PersistenceContext
- JPA에서 EntityManager를 주입하기 위한 annotation
- Spring이나 JPA 환경에서는 EntityManager를 직접 생성하지 않고, @PersistenceContext 애너테이션을 통해 의존성 주입을 받음.
EntityManager
- 데이터베이스와의 상호작용을 관리하는 JPA의 핵심 클래스
- Entity 객체를 데이터베이스에 저장하고 조회, 수정, 삭제(CRUD) 등을 수행함.
save(Member member) 메서드
- em.persist(member):
- persist 메소드는 Member 객체를 데이터베이스에 저장함.
- 해당 객체는 데이터베이스에서 관리되는 상태가 됨.
find(Long id) 메서드
- em.find(Member.class, id)
- Member.class 는 어떤 엔티티 타입을 조회할지 명시하는 역할 → 여기서는 Member 엔티티
- id는 찾으려는 Member 객체의 고유 식별자(Primary Key)
2. 도메인 분석 설계
JPA에서의 연관관계 매핑 종류
- 1:1 관계 (@OnetoOne)
- 외래 키는 두 엔티티 중 한 곳에만 존재하며, 이 외래 키를 통해 서로 연결된다.
- @JoinColumn을 사용하여 외래 키를 명시적으로 설정한다.
- 1:N 관계 (@OnetoMany)
- 외래 키는 N쪽 엔티티에 존재한다.
- mappedBy 속성을 사용하여 연관 관계의 주인을 설정하고, 외래 키는 연관된 N쪽 엔티티에서 관리한다.
- N:1 관계 (@ManytoOne)
- 외래 키는 N쪽 엔티티에 존재하며, N쪽 테이블이 외래 키를 관리한다.
- @JoinColumn을 사용하여 외래 키를 명시적으로 설정한다.
- N:N 관계 (@ManytoMany) —> 실무에선 사용하지 않음
- @JoinTable을 사용하여 연결 테이블을 정의한다.
주요 개념
- @JoinColumn
- 연관된 엔티티의 외래 키를 관리하는 칼럼을 명시적으로 설정하는 데 사용된다.
- 외래 키가 있는 테이블에서(N쪽) 해당 키를 사용해 다른 엔티티와의 관계를 연결한다.
- 주로 @ManyToOne 관계에서 많이 사용되며, 1:1 관계에서도 사용 가능하다.
- @JoinTable
- 다대다(N:N) 관계에서 중간 테이블을 생성할 때 사용된다.
- 두 테이블 간의 다대다 관계를 관리하는 연결 테이블을 정의한다. 연결 테이블은 양쪽 엔티티의 외래 키를 가진다.
- @ManyToMany 관계에서 사용된다.
- mappedBy
- 연관 관계의 주인이 아니고, 연관된 엔티티에서 외래 키를 관리하는 속성을 설정할 때 사용된다.
- @OneToMany나 @ManyToMany에서 사용된다.
연관관계의 주인(Owner)과 비주인(Non-Owner)
- 연관 관계의 주인:
- 외래 키를 관리하는 엔티티
- 주로 @ManyToOne이나 @JoinColumn이 있는 엔티티가 주인 역할이다.
- 연관 관계의 비주인:
- mappedBy로 설정된 엔티티
- 외래 키를 직접 관리하지 않으며, 주인 엔티티에서 관리되는 외래 키를 참조한다.
‼️엔터티 설계시 주의점
1. 엔티티에는 가급적 Setter 사용X
- 변경 포인트가 많아서 유지보수가 어렵다.
2. 모든 연관관계는 지연로딩으로 설정
- 즉시로딩( EAGER )은 예측이 어렵고, 어떤 SQL이 실행될지 추적하기 어렵다. 특히 JPQL을 실행할 때 N+1 문제가 자주 발생한다. → 불필요한 쿼리를 줄여준다.
- 실무에서 모든 연관관계는 지연로딩( LAZY )으로 설정해야 한다.
- @XToOne(OneToOne, ManyToOne) 관계는 기본이 즉시로딩이므로 직접 지연로딩으로 설정해야 한다.
3. 컬렉션은 필드에서 초기화
- 컬렉션 타입의 필드를 초기화하지 않으면, 해당 필드를 사용하는 시점에 그 필드가 null일 수도 있다.
List<Order> orders = null;
- 이렇게 선언만 하고 초기화하지 않으면, 나중에 orders.add(order)와 같은 작업을 할 때 NPE가 발생한다. 왜냐하면 orders가 아직 생성되지 않았기 때문에 null 상태에서 메서드를 호출할 수 없기 때문이다.
private List<Order> orders = new ArrayList<>();
- 이렇게 하면 필드가 항상 빈 리스트로 초기화되기 때문에, 나중에 그 필드를 사용할 때 null이 아닌 빈 리스트 상태에서 작업할 수 있다.
4. 양방향 연관 관계 매서드
- 양방향 관계인 두 엔티티 간의 연관을 설정할 때, 서로의 필드를 동시에 업데이트하기 위한 역할
//==연관 관계 메서드==//
public void setMember(Member member) {
this.member = member; // Order의 member 필드 설정
member.getOrders().add(this); // Member의 orders 리스트에 현재 Order 추가
}
- setMember 메서드는 Order 엔티티가 Member 엔티티와 연관 관계를 맺을 때 호출된다.
- 이 메서드는 먼저 this.member = member로 현재 Order 객체가 가리키는 member를 설정한다.
- member.getOrders().add(this)를 호출해서 Member 엔티티의 orders 리스트에 현재 Order 객체를 추가한다.
//==연관 관계 메서드==//
public void addOrderItem(OrderItem orderItem){
orderItems.add(orderItem); // orderItems 리스트에 orderItem 추가
orderItem.setOrder(this); // 현재 Order 객체를 orderItem에 설정
}
- OrderItem을 Order에 추가하는 메서드
- orderItems.add(orderItem)으로 Order의 orderItems 리스트에 새 OrderItem을 추가한다.
- orderItem.setOrder(this)를 호출해서 해당 OrderItem 객체가 가리키는 Order 필드를 현재 Order로 설정한다.
3. 애플리케이션 구현 준비
- 요구사항 분석
- 계층형 구조 사용
- controller, web: 웹 계층
- service: 비즈니스 로직, 트랜잭션 처리
- repository: JPA를 직접 사용하는 계층, 엔티티 매니저 사용
- domain: 엔티티가 모여 있는 계층, 모든 계층에서 사용
이번 글에서는 JPA를 활용한 웹 애플리케이션 개발의 기초적인 부분을 다뤘습니다.
이어지는 2편에서는 도메인 설계를 실제 코드로 구현하면서 회원, 상품, 주문 도메인의 개발 과정을 살펴보겠습니다.
'Backend > SpringBoot' 카테고리의 다른 글
Jackson 매핑 오류: JSON 필드와 Java 필드 불일치 문제 해결하기 (feat. 모델 api 연결) (1) | 2025.02.21 |
---|---|
웹 서버(Web Server) vs 웹 애플리케이션 서버(WAS) (1) | 2025.02.10 |
<실전! 스프링 부트와 JPA 활용1 - 웹 애플리케이션 개발> 2편 (0) | 2025.02.10 |