Notice
Recent Posts
Recent Comments
| 일 | 월 | 화 | 수 | 목 | 금 | 토 |
|---|---|---|---|---|---|---|
| 1 | 2 | 3 | 4 | |||
| 5 | 6 | 7 | 8 | 9 | 10 | 11 |
| 12 | 13 | 14 | 15 | 16 | 17 | 18 |
| 19 | 20 | 21 | 22 | 23 | 24 | 25 |
| 26 | 27 | 28 | 29 | 30 |
Tags
- 코틀린
- js
- GraphQL
- css
- java
- 노개북
- html
- Android
- 개발
- C++
- 안드로이드 개발
- springboot
- 안철수
- linux
- hcj
- 구글
- build.gradle
- 안드로이드
- kotlin
- Eclipse
- 보안
- 하버드
- gradle
- Android 4.1
- ActiveX
- 탐지기법
- JavaScript
- 리눅스
- 자바
Archives
- Today
- Total
꿈소년의 개발 이야기
[스프링 부트 개발자 온보딩 가이드 스터디] Chapter 05 고급 JPA 기반의 마이크로블로그 REST API 서버 개발 본문
Do it 스터디!/스프링 부트 개발자 온보딩 가이드 스터디!
[스프링 부트 개발자 온보딩 가이드 스터디] Chapter 05 고급 JPA 기반의 마이크로블로그 REST API 서버 개발
fogthegreat 2026. 4. 3. 20:19반응형
DAY 5
🔖 오늘 읽은 범위 :
🌱공부 내용: Chapter 05 고급 JPA 기반의 마이크로블로그 REST API 서버 개발
👢쪽수: p.151-p.218
- 목표: REST API 제공하는 마이크로블로그 스프링부트 앱 구현.
- 기능 요구 사항
- 사용자 계정 CRUD 수행.
- 게시글 데이터 CRUD 수행.
- 다른 사용자에 대한 팔로우 정보 CRUD 수행.
- 감사 기능을 통한 데이터 변경 이력 추적 수행.
- 인증 기능 미제공.
- 구현 요구 사항
- 엔드포인트: 모든 API 엔드포인트는 ‘ /api/todos/v1’ 으로 시작한다.
- 테스트: CRUD 기능 유닛 테스트.
- 문서화 및 테스트: 스웨거3 사용한 API 문서화 및 테스트.
프로젝트 초기화
프로젝트 스캐폴드 생성 및 다운로드
스프링 이니셜라이저
| 옵션 | 값 | 설명 |
|---|---|---|
| dependencies | web | REST API 서버 개발 핵심 의존성 ‘org.springframework.boot’ 추가. |
| 서블릿 컨테이너 톰캣 내장. 스프링 MVC 기반 앱, REST API 서버 개발에 필요한 클래스 라이브러리 제공. | ||
| javaVersion | 21 | 프로젝트 자바 버전 설정. |
| type | gradle-project | 빌드 도구로 gradle 설정. |
| bootVersion | 3.3.1 | 사용할 Spring Boot 버전 설정. |
| groupId | com.asdf | 프로젝트 그룹 아이디 설정. |
| name | minilog | 프로젝트 이름 설정. |
| artifactId | minilog | 프로젝트 아티팩트 아이디 설정. 프로젝트 고유 식별자. 생성된 jar 파일 이름으로 사용 됨. |
| packageName | com.asdf.minilog | 기본 패키지 이름 설정. 코드 네임스페이스 정의. |
curl https://start.spring.io/starter.zip \
-d dependencies=web \
-d type=gradle-project \
-d bootVersion=3.3.1 \
-d groupId=com.asdf \
-d name=minilog \
-d artifactId=minilog \
-d packageName=com.asdf.minilog \
-o minilog-jpa.zip
도커 MySQL 설치 및 설정
minilog용 MySQL 도커 컨테이너 실행
docker run --name mysql-minilog \
-e MYSQL_ROOT_PASSWORD=dev_password \
-e MYSQL_DATABASE=minilog_db \
-e MYSQL_USER=minilog_user \
-e MYSQL_PASSWORD=dev_password \
-p 3307:3306 \
-v mysql-minilog-data:/var/lib/mysql \
-d mysql:8.0
- 호스트 3307 포트를 이용해서 도커 컨테이너의 3306 포트에 접속할 수 있도록 한다.
Minilog API 서버 구현
- 고수준 JPA.
- 스프링 전역 예외 처리.
- 감사 기능을 이용한 데이터 변경 추적 방법.
- JPA 활용.
- 관계 매핑 애노테이션 이해.
스프링 전역 에러 처리기 작성
- Global Exception Handler
- 스프링 부트 애플리케이션에서 발생하는 예외를 한 곳에서 일관되게 처리하기 위한 장치.
- 예외 처리 상황을 중앙에서 제어하고 처리할 수 있다.
- @ControllerAdvice
- 스프링 프레임워크에서 제공하는 애노테이션.
- 전역적인 예외 처리, 데이터 바인딩, 모델 객체에 대한 조언(Advice)을 설정할 수 있다.
- 조언 ⇒ 스프링 AOP 의 조언을 의미함.
- AOP 핵심: 핵심 로직에 개입하지 않고도 실행 과정 전후나 특정 시점에 부가적인 동작을 삽입할 수 있다는 점.
- 컨트롤러 메서드 실행 전후, 예외 발생 시점에 개입해 공통 기능을 제공한다.
- 할 수 있는 일들.
- 일관된 예외 처리 로직 수행.
- 데이터 바인딩 규칙 설정.
- 모든 컨트롤러에 공통 모델 데이터 추가.
- 애플리케이션 전반에 걸쳐 여러 컨트롤러에서 반복하는 예외 발생을 한 곳에서 처리 가능하다.
- @ExceptionHandler 와 조합해서 함께 사용한다.
- 모든 컨트롤러에 기본 적용되나, 속성을 지정해서 특정 패키지나 클래스에만 적용할 수 있다.
- 개별 컨트롤러에 @ExceptionHandler 가 정의되어 있다면, 해당 핸들러가 우선 적용된다.
엔티티, DTO, 매퍼 구현
- 엔티티 관계 정의.
- OneToMany
- ManyToOne
- 엔티티 역할 및 속성 정의.
- 생성 시간 createdAt, 수정 시간 updatedAt ⇒ 감사 목적을 위한 추적.
엔티티 작성
- 감사 기능
- 데이터가 언제 생성되고, 마지막으로 수정되었는지 추적한다.
- @CreatedDate
- 레코드 처음 생성 시간을 자동 기록한다.
- @LastModifiedDate
- 레코드 마지막 수정 시간을 기록한다.
- @EntityListeners(AuditingEntityListener.class) 를 통해 추가된다.
- 필드 관계 설정
- @OneToMany(mappedBy = “author”, cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.LAZY)
- mappedBy = “author”
- 1:N, 일대다 관계를 맺을 때, mappedBy 로 지정한 필드를 통해서 형성한다.
- cascade = CascadeType.ALL
- 엔티티의 변경 사항이 관계 된 엔티티에도 전파되도록 설정한다.
- 단일 부모 엔티티에서 특정 엔티티를 일대다의 다수 엔티티들의 컬렉션에서 제거해도 자동으로 삭제 되지 않는다.
- 자동 삭제하려면 orphanRemoval 값을 설정해줘야 한다.
- orphanRemoval = true
- 부모 엔티티의 다수 관계의 엔티티 컬렉션에서 특정 엔티티를 제거할 때, 해당 엔티티가 데이터베이스에서도 자동 삭제 된다.
- 만약, 부모 엔티티가 삭제될 때, 다수 쪽 엔티티 컬렉션이 모두 삭제 되려면 CascadeType.REMOVE 를 명시해야 한다.
- fetch = FetchType.LAZY
- 부모 엔티티 조회할 때, 연관된 다수 쪽 엔티티 컬렉션이 즉시 로딩되지 않고, 실제로 접근할 때 JPA 가 SELECT 쿼리를 추가로 실행해서 데이터를 가져온다.
- FetchType.EAGER 를 설정하면 JPA 구현체 hibernate 는 JOIN 또는 별도의 SELECT 쿼리를 사용해 다수쪽 엔티티 컬렉션을 즉시 로딩하도록 한다.
- mappedBy = “author”
- @ManyToOne(fetch = FetchType.EAGER)
- N:1, 다대일 관계를 만든다.
- FetchType.EAGER: 조회 시 유저 정보도 즉시 로딩된다.
- @JoinColumn(name = “author_id”, nullable = false)
- @JoinColumn: 해당 엔티티에서 다른 엔티티의 ID를 참조하는 외래 키(FK)를 정의하는 데 사용한다.
- 해당 엔티티 테이블의 author_id 컬럼이 다른 엔티티 테이블의 ID 값을 참조할 수 있도록 설정된다.
- nullable = false: 이 설정으로 통해 무결성을 보장한다.
- @JoinColumn: 해당 엔티티에서 다른 엔티티의 ID를 참조하는 외래 키(FK)를 정의하는 데 사용한다.
- @Index
- 특정 필드에 인덱스를 설정한다.
- 조회 성능을 향상 시킨다.
- @UniqueConstraint(columnNames = {”follower_id”, “followee_id”})
- follower_id 와 followee_id 의 조합이 고유해야 함을 보장하는 제약 조건을 만든다.
- 이 제약 조건으로 중복 저장되지 않도록 하여 데이터 일관성을 제공한다.
- @OneToMany(mappedBy = “author”, cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.LAZY)
DTO 작성
- DTO 객체: 컨트롤러와 서비스 계층 간 데이터 교환을 위해 사용한다.
- 엔티티 직접 노출이 되지 않아, 데이터 보호에 유리하며, 전송해야 할 데이터만 선별해서 불필요한 데이터 전송을 최소화할 수 있다.
리포지토리 레이어 구현
- 스프링 데이터 JPA 핵심 기능 3가지
- JpaRepository 인터페이스 상속하여 구현체를 자동 생성하는 기능.
- save(), delete(), findById() 같은 JpaRepository 기본 메서드 제공한다.
- 메서드 이름 기반으로 쿼리 유추하여 실행하는 파생 쿼리 메서드 제공한다.
- 파생 쿼리 Derived Query
- Query Method; 파생 쿼리 메서드.
- 메서드 이름의 네이밍 규칙을 분석해 내부적으로 쿼리를 자동 생성한다.
- JpaRepository에서 제공하지 않는 조회 기능이 필요한 경우 유용하다.
- 예시
- findById(): 별도 구현없이 바로 사용할 수 있는 기본 Jpa 메서드로 제공된다.
- findByUsername(): username 필드 값이 메서드에 전달된 인자와 같은 레코드를 탐색하는 기능을 수행함. 선언만 해두면 런타임에 자동으로 생성된다. By 는 검색 조건의 시작을 의미한다.
- findByFollowerIdAndFolloweeId(): And 를 통해 두 필드 followerId, followeeId 를 조건으로 지정하여 주어진 값과 일치하는지 확인하는 쿼리가 자동 생성된다.
- JPQL
- Java Persistence Query Language
- 더 복잡한 조회나 조건이 필요한 경우 사용할 수 있다.
- JPA 엔티티와 속성을 대상으로 동작하는 객체 지향 쿼리 언어이다.
- 리포지토리 메서드에 @Query 애노테이션을 붙여 직접 작성한다.
- JPA 구현체(Hibernate)는 작성된 JPQL → SQL 로 변환해서 처리한다.
- 단순 파생 쿼리로 표현하기 어려운 복잡한 조인, 정렬, 조건 기반 조회 등을 구현할 때 사용한다.
- JpaRepository 인터페이스 상속하여 구현체를 자동 생성하는 기능.
서비스 레이어 구현
- 클래스에 @Transactional 애노테이션을 적용하는 경우.
- 클래스 내 모든 메서드에 트랜잭션을 적용한다.
- 데이터 변경 작업이 안전하게 하도록 보장한다.
- 예외 발생 시 자동 롤백을 수행한다.
- 특정 메서드는 읽기 연산을 위한 성능 최적화와 데이터 무결성 보장하기 위해 별도로 @Transactional(readOnly = true) 로 설정하기도 한다.
- 쓰기 잠금을 생략하여 리소스를 절약한다.
- 조회 성능을 높일 수 있다.
- 트랜잭션이 종료될 때 변경 내용을 커밋하지 않도록 처리해서, 예상 못한 데이터 변경을 방지 할 수 있다.
- 클래스에 @Transactional(isolation = Isolation.REPEATABLE_READ) 애노테이션을 적용하는 경우.
- 데이터베이스 트랜잭션의 일관성과 무결성을 보장하기 위해 트랜잭션 격리 수준을 지정한다.
- Isolation.REPEATABLE_READ: 트랜잭션 내에서 같은 데이터를 반복 조회할 때, 다른 트랜잭션에 의해 수정된 내용이 보이지 않도록 보호하는 격리 수준이다. 균형 잡힌 격리 수준으로 본다.
- 데이터 조회 시 일관성 유지한다.
- 트랜잭션 진행 중 다른 곳의 데이터 변경으로 인한 불일치 문제를 방지 할 수 있다.
- 격리 수준이 높아질수록 잠금(Lock)이 많이 발생해서 성능에 악영향을 줄 수도 있다.
- 성능과 데이터 일관성 사이의 균형을 고려하여 선택해야 한다.
반응형
'Do it 스터디! > 스프링 부트 개발자 온보딩 가이드 스터디!' 카테고리의 다른 글
| [스프링 부트 개발자 온보딩 가이드 스터디] Chapter 06 Minilog에 인증 기능 추가하기 (1) | 2026.04.05 |
|---|---|
| [스프링 부트 개발자 온보딩 가이드 스터디] 복잡한 실제 비즈니스 요구사항과 JPA 코드 구조 잡기 (0) | 2026.04.03 |
| [스프링 부트 개발자 온보딩 가이드 스터디] Chapter 04 JPA 기반의 To-Do 리스트 REST API 서버 개발 (0) | 2026.04.03 |
| [스프링 부트 개발자 온보딩 가이드 스터디] Chapter 03. 인메모리 기반의 To-Do 리스트 REST API 서버 만들기 (0) | 2026.04.03 |
| [스프링 부트 개발자 온보딩 가이드 스터디] Chapter 02 스프링 부트란 무엇인가요? (0) | 2026.04.02 |
