본문 바로가기
dev/프로젝트

[프로젝트] MVC 아키텍처 & JPA

by dev-everyday 2025. 1. 14.
반응형

1. MVC 아키텍처

1. DTO (Data Transfer Object)

a) 클라이언트와 서버 사이에서 데이터를 전송하기 위한 객체이다.

b)  Controller 계층에서 Request/Response 용도로 사용한다.

 c) Entity를 직접 노출하기보다 DTO로 주고받는 편이 좋다(보안, 유지보수 측면).

2. Controller

주로 DTO 유효성 검증 및 요청/응답을 처리한다.

Controller에 Entity를 직접 두는 것은 좋은 설계가 아니다(관심사 분리).

(예: controller -> service -> repository 구조로 진행)

3. Repository

JPA에서는 Entity 중심으로 DB에 접근하는 계층이다.

일반적인 흐름은 controller(dto) -> service(dto, entity) -> repository(entity).

Repository는 DB 접근 로직을 담당하고, 핵심 비즈니스 로직 및 데이터 정합성 검증은 Service가 담당한다.

4. Service

DTO와 Entity를 모두 처리하며, 비즈니스 로직을 수행한다.

트랜잭션 범위 안에서 데이터 정합성을 검증하고, 필요한 경우 Repository를 호출해 DB에 접근한다.

2. Annotation

@RestController vs @Controller

@Controller: View(템플릿) 렌더링을 주로 담당.

@RestController: @ResponseBody + @Controller를 합친 것으로, JSON 등 데이터 자체를 반환하기에 적합.

API 서버라면 @RestController를, 템플릿 엔진을 사용할 경우 @Controller를 주로 쓴다.

@Controller, @Service, @Repository, @Component

전부 @Component를 메타로 하는 스테레오타입 애노테이션이다.

@Service, @Repository는 각각 비즈니스 로직 계층, DB 접근 계층임을 명시적으로 나타내 유지보수를 용이하게 한다.

@Configuration은 @Component를 포함하여, 클래스 단위로 Bean 등록을 위한 설정을 모아두는 용도다.

@Bean은 @Configuration 내부의 메서드에 붙여서 Bean 생성을 명시한다.

@ComponentScan

@SpringBootApplication 내부에 포함되어 있으며, @Component 계열(@Controller, @Service, @Repository 등)과 @Configuration을 찾아서 Bean으로 등록한다.

등록된 클래스들은 BeanFactory에 의해 인스턴스화되고 관리된다.

Bean 등록

간단히 말해, 스프링 컨테이너가 객체를 생성(new)하고 필요한 의존성을 주입(생성자 주입 등)하여 관리하는 과정을 말한다.

클래스가 인스턴스화될 때 생성자가 실행되고, 필요한 Bean들이 자동으로 연결된다.

final 전역 상수

final 키워드를 사용해 불변(Immutable) 필드를 선언하고, 생성자에서 주입 받는 패턴을 자주 쓴다(생성자 패턴).

이를 통해 값이 한 번 설정된 후 변경되지 않도록 보장한다.

정리

@ComponentScan으로 스캔된 클래스들은 BeanFactory에 등록(인스턴스화)된다.

인스턴스화 시점에 생성자가 실행되고, 필요한 Bean들이 자동으로 주입된다.

3. JPA

JpaRepository

JpaRepository<Entity, ID> 형태로 상속받으면, 기본적인 CRUD 메서드가 제공된다.

메서드 이름으로 쿼리를 만드는 방법이 복잡해지면 @Query 애노테이션과 JPQL을 사용한다.

JPA 설정(ddl-auto)

spring.jpa.hibernate.ddl-auto=update일 경우 Entity 스키마가 변경되었을 때 컬럼 삭제 등은 자동 반영되지 않는다.

개발 단계에서는 create-drop을 써서 부트 시점마다 DB를 새로 만들 수도 있다(데이터도 함께 삭제되므로 주의).

DDL

@Entity가 선언된 클래스는 테이블로 매핑되고, @Id로 PK를 지정하며, @GeneratedValue로 채번 전략을 설정한다.

@ManyToOne, @OneToMany, @JoinColumn 등을 통해 관계를 설정한다.

fetch 전략으로 LAZY/EAGER를 선택할 수 있는데, LAZY는 실제 필요 시점에, EAGER는 즉시(조인 또는 추가 SELECT 등) 로딩한다.

JPA N+1 문제

ORM 기술에서 특정 객체를 대상으로 수행한 쿼리가 해당 객체가 가지고 있는 연관관계 또한 조회하게 되면서 N번의 추가적인 쿼리가 발생하는 문제다.

fetch join(@Query 사용)으로 한 번에 가져오거나, 필요 시점에만 LAZY 로딩 등을 활용해 해결한다.

상황에 따라 EAGER, LAZY를 적절히 선택하고 limit 등을 설정해 성능을 조절할 수 있다.

더보기
 
서비스 기획별로 처음부터 데이터가 존재해야 유리하다면 패치 조인을 이용해 처음부터 데이터를 가져와서 관리하였고 데이터의 개수를 필요한 만큼만 가져오도록 limit를 설정하여 관리하였다. 그리고 만약에 조회가 이후 어떤 작업 후 이루어진다면 lazy 조인으로 작동하도록 하였다.

4. TODO

- JPA를 포함한 MVC 구조의 프로젝트 생성

- ERD 그리기(테이블 5개 이내)

- Entity 클래스 작성

- Docker로 MySQL 컨테이너 띄우기

- Spring 설정(yml/properties)에서 DB 연결 정보 등록

반응형