공부일기
[Spring Boot 입문] MiniSNS 프로젝트로 배우는 백엔드 기본 구조 (Controller / Service / Repository / Entity) 본문
[Spring Boot 입문] MiniSNS 프로젝트로 배우는 백엔드 기본 구조 (Controller / Service / Repository / Entity)
석새우 2026. 3. 6. 13:34https://github.com/seokMini-2/mySpring
1. 프로젝트를 시작한 이유
Spring Boot를 처음 공부하면서 가장 어려웠던 점은 “이 프레임워크가 도대체 어떻게 돌아가는지”였다.
- GET / POST는 뭐지?
- 왜 Repository는 구현도 안 했는데 동작하지?
- save()를 안 했는데 DB가 업데이트 되는 이유는?
- DTO는 왜 쓰는 걸까?
이런 의문을 해결하기 위해 간단한 SNS 서버(MiniSNS)를 직접 만들어보면서 스프링의 핵심 구조를 이해해 보기로 했다.
이 프로젝트의 목표는 다음과 같다.
- Spring Boot 기본 구조 이해
- REST API 설계 경험
- JPA 기반 데이터 처리
- DTO 기반 API 응답 설계
2. MiniSNS 프로젝트 기능
프로젝트에서 구현한 기능은 다음과 같다.
User
- 사용자 생성
- 사용자 목록 조회
Post
- 게시글 생성
- 게시글 조회
- 게시글 수정
- 게시글 삭제
Comment
- 댓글 생성
- 댓글 조회
- 댓글 삭제
추가적으로 다음 기능도 구현했다.
- 페이징 조회
- DTO Projection
- 글로벌 예외 처리
3. 스프링 백엔드 구조 이해하기
Spring Boot 프로젝트는 일반적으로 계층 구조(Layered Architecture)를 사용한다.
이번 프로젝트에서도 다음 구조로 구현했다.
| 계층 | 역할 | 비유 |
| Controller | HTTP 요청 처리 | 홀 직원 |
| Service | 비즈니스 로직 | 요리사 |
| Repository | DB 접근 | 냉장고 |
| Entity | 데이터 모델 | 재료 |
4. Controller: HTTP 요청을 처리하는 계층
Controller는 클라이언트 요청을 받는 역할을 한다.
예를 들어 클라이언트가 다음 요청을 보냈다고 하자.
POST /posts
그러면 Spring은 해당 URL을 처리하는 Controller 메서드를 찾는다.
예시 코드
@RestController
@RequestMapping("/posts")
public class PostController {
private final PostService postService;
@PostMapping
public PostResponse create(@RequestBody CreatePostRequest request) {
return postService.create(request.userId(), request.title(), request.content());
}
}
여기서 중요한 어노테이션을 살펴보자.
@RestController
Spring 공식 문서 기준으로 @RestController는
Controller + ResponseBody 기능을 합친 어노테이션이다.
즉
- HTTP 요청을 처리하고
- 반환 객체를 JSON으로 변환한다.
@RequestBody
이 어노테이션은 HTTP 요청 Body(JSON)를 Java 객체로 변환한다.
예를 들어 다음 JSON이 들어오면
{
"userId": 1,
"title": "hello",
"content": "first post"
}
Spring은 이를 자동으로 DTO 객체로 변환한다.
이 작업은 Jackson 라이브러리가 담당한다.
5. Service: 비즈니스 로직 계층
Controller는 요청을 받아 Service에 로직을 위임한다.
Service는 다음 역할을 한다.
- 데이터 검증
- 비즈니스 규칙 처리
- 트랜잭션 관리
예시 코드
@Service
public class PostService {
private final PostRepository postRepository;
private final UserRepository userRepository;
public PostResponse create(Long userId, String title, String content) {
User user = userRepository.findById(userId)
.orElseThrow(() -> new IllegalArgumentException("유저 없음"));
Post post = new Post(title, content, user);
return PostResponse.toResponse(postRepository.save(post));
}
}
6. 트랜잭션(Transaction)이란?
서비스 계층에서 가장 중요한 개념 중 하나가 트랜잭션이다.
트랜잭션은 쉽게 말해
"여러 DB 작업을 하나의 작업 단위로 묶는 것"
예를 들어 은행 송금을 생각해 보자.
A 계좌 -1000
B 계좌 +1000
이 두 작업은 반드시 함께 성공하거나 함께 실패해야 한다.
이것이 바로 트랜잭션이다.
Spring에서는 @Transactional 어노테이션으로 트랜잭션을 선언할 수 있다.
@Transactional
public void updatePost(...) { ... }
Spring 공식 문서에서도 다음과 같이 설명한다.
@Transactional을 사용하면 해당 메서드는 데이터베이스 트랜잭션 안에서 실행된다.
즉
메서드 시작 → 트랜잭션 시작
메서드 종료 → commit
에러 발생 → rollback
이 과정이 자동으로 처리된다.
7. Dirty Checking (더티 체킹)
JPA를 사용하면서 가장 놀라웠던 점 중 하나는 다음이었다.
save()를 안 했는데 DB가 업데이트된다?
DB가 자동으로 업데이트 된다는데 무슨 소리지?
다음 코드를 보자.
@Transactional
public PostResponse update(Long id, String title, String content) {
Post post = postRepository.findById(id)
.orElseThrow(() -> new PostNotFoundException(id));
post.update(title, content);
return PostResponse.toResponse(post);
}
여기서는 save()를 호출하지 않는다.
그런데도 DB는 업데이트 된다.
이것이 JPA Dirty Checking 때문이다.
더티 체킹은 다른 말로 변경 감지이다.
조사하다 보니 JPA의 아주 큰 장점이자 특징이라는 것을 알게 되었다.
즉, 더티 체킹은 트랜잭션 안에서 엔티티의 변경이 일어나면, 이를 감지하는 JPA 특징이다.
더티 체킹과 관련된 기능이 JPA의 플러시(flush)다.
플러시는 영속성 컨텍스트의 감지된 변경내용을 데이터베이스에 반영하는 기능이다.
JPA의 또 다른 특징 중 하나는 Query 쓰기 지연을 지원이다.
이는 쉽게 말하면, JPA를 통해 전송할 쿼리들을 코드 동작 후 즉시 사용된다기보다, 트랜잭션이 성공적으로 끝나는 시점에 한 번에 모아서 사용하는 것을 의미한다.따라서 플러시의 역할은 SQL 저장소에 쌓여있는 쿼리(등록, 수정, 삭제)를 데이터베이스에 전송하는 것이다.
1️⃣ Entity 조회
2️⃣ 트랜잭션 안에서 Entity 값 변경
3️⃣ 트랜잭션 종료 시 변경 감지
4️⃣ UPDATE 쿼리 자동 실행
즉 JPA는 하나의 트랜잭션 내에서 변경된 객체 상태를 감지해서 DB에 반영한다.
8. Repository: DB 접근 계층
Repository는 데이터베이스와 직접 통신하는 계층이다.
Spring Data JPA를 사용하면 Repository 구현을 직접 작성하지 않아도 된다.
예시
public interface PostRepository extends JpaRepository<Post, Long> {
}
이 인터페이스만 작성하면 다음 메서드를 자동으로 사용할 수 있다.
save()
findById()
findAll()
delete()
등등...
Spring Data JPA 공식 문서에서는 다음과 같이 설명한다.
Spring Data JPA는 JPA 기반 데이터 접근을 쉽게 하기 위해 Repository 추상화를 제공한다.
즉 개발자는
- SQL 작성
- EntityManager 관리
같은 작업을 직접 하지 않아도 된다.
9. Entity: 데이터 모델
Entity는 DB 테이블과 매핑되는 객체이다.
예시
@Entity
public class Post {
@Id
@GeneratedValue
private Long id;
private String title;
private String content;
@ManyToOne
@JoinColumn(name = "user_id")
private User user;
}
이렇게 하면 다음과 같은 테이블이 생성된다.
post
-----------------
id
title
content
user_id
| 어노테이션 | 역할 |
| @Entity | JPA 엔티티 선언 |
| @Id | 기본키 |
| @GeneratedValue | 자동 증가 |
| @ManyToOne | 관계 설정 |
| @JoinColumn | 외래키 컬럼 지정 |
10. 이번 글에서 배운 것
이번 글에서는 Spring Boot 프로젝트의 기본 구조를 살펴보았다.
핵심 개념을 정리하면 다음과 같다.
- Controller → HTTP 요청 처리
- Service → 비즈니스 로직
- Repository → DB 접근
- Entity → DB 모델
또한 다음 개념을 이해했다.
- Transaction
- Dirty Checking
- Spring Data JPA Repository