[SOPT 세미나] 3차 - Thread부터 DB까지

시훈·2025년 5월 18일

SOPT 36기

목록 보기
4/6
post-thumbnail

🧵 1. 자바는 싱글 프로세스, 멀티 스레드 구조이다

JVM은 싱글 프로세스 기반의 애플리케이션이지만, 그 안에서 여러 스레드가 동시에 동작한다. 내가 생각하는 이 구조의 핵심은 다음과 같다.

  • main 스레드는 애플리케이션의 진입점을 실행한다.
  • GC(Garbage Collector) 스레드는 백그라운드에서 객체 정리를 처리한다.
  • 애플리케이션에서 우리가 새로 생성하는 스레드, 혹은 Spring Boot가 내부적으로 사용하는 워커 스레드들도 모두 이 JVM 프로세스 내에 존재한다.

즉, 자바는 기본적으로 멀티스레딩 환경을 전제로 만들어진 언어이며, 이 점은 이후 웹 요청 처리나 비동기 처리에서 반드시 고려해야 한다.


🌐 2. HTTP 요청은 어떻게 처리될까?

Spring Boot에서 HTTP 요청이 들어오면 어떻게 처리될까? 이번 세미나에서 가장 실질적인 흐름을 이해할 수 있었던 부분이다.

  1. Spring Boot는 기본적으로 Tomcat이라는 내장 WAS(Web Application Server)를 사용한다.
  2. Tomcat은 실행 시 스레드풀(기본 200개)을 생성해놓는다.
  3. 클라이언트로부터 요청이 들어오면, 스레드풀에서 남아있는 워커 스레드 하나를 꺼내서 해당 요청을 처리한다.
  4. 처리 후 스레드는 다시 풀로 돌아간다.

이 구조는 스레드풀 기반 요청 처리 구조라고 부르며, 핵심은 "요청 하나당 스레드 하나가 배정된다"는 점이다.


🧪 3. 데이터베이스는 어떻게 연결되고 통신하는가?

요청을 처리하는 중 DB 작업이 필요한 경우, 워커 스레드는 직접 DB에 접근하지 않는다. 대신, Spring은 HikariCP라는 커넥션 풀 라이브러리를 통해 미리 만들어둔 DB 연결 객체(Connection)를 재활용한다.

  • 워커 스레드는 작업 중 커넥션 풀이 가진 커넥션을 하나 빌려 사용한다.
  • 커넥션이 부족하면 대기하거나 실패한다.
  • 커넥션이 너무 많아도 DB에 과부하가 걸릴 수 있다.

🔸 적절한 커넥션 풀 크기를 유지하는 것이 실제 서비스에서 매우 중요한 포인트임을 배웠다.

🔸 기본값은 10이며, (CPU 코어 수 * 2) + 1 정도로 시작하는 것을 추천한다고 한다.


💡 4. Spring의 철학 – Bean, IoC, DI

이전 과제에서 new 키워드로 직접 객체를 생성하던 방식은 확장성과 유지보수에 취약하다는 단점이 있었다. 이를 해결하기 위해 Spring은 다음과 같은 구조를 제공한다.

  • IoC (제어의 역전): 객체의 생명주기와 의존성 관리를 개발자가 아닌 프레임워크가 담당하는 구조이다.
  • DI (의존성 주입): 필요한 객체를 생성자 또는 필드 등을 통해 자동으로 주입받는 방식이다.
  • Bean: Spring이 관리하는 객체를 의미하며, @Component, @Service, @Repository, @Controller 등을 통해 등록할 수 있다.

아래와 같이 생성자 주입만 선언해두면, Spring이 알아서 Bean을 찾아 넣어준다.

@Service
public class PostService {
    private final PostRepository postRepository;

    public PostService(PostRepository postRepository) {
        this.postRepository = postRepository;
    }
}

이제는 의존 관계를 외부에서 관리하게 되므로, SOLID 원칙 중 DIP(의존성 역전 원칙) 도 자연스럽게 지킬 수 있다.


🚨 5. 예외 처리는 왜 중요한가?

처음에는 단순히 try-catch를 쓰는 게 예외 처리라고 생각했다. 하지만 스프링 기반의 웹 서버는 다른 관점에서 예외를 처리해야 한다.

  • 단순히 로그 출력이 아니라, 클라이언트에게 적절한 응답을 반환해야 한다.
  • 예외의 종류에 따라 HTTP 상태 코드도 다르게 응답해야 한다.
  • 그렇지 않으면 무조건 500 Internal Server Error만 발생하게 된다.

📦 이번에 이해한 스프링의 예외 처리 흐름

  1. 서비스 계층 등에서 IllegalArgumentException 같은 예외를 throw 한다.
  2. @RestControllerAdvice를 통해 전역적으로 예외를 잡는다.
  3. 예외 종류에 따라 HTTP 상태 코드와 메시지를 담은 ResponseEntity를 반환한다.
@RestControllerAdvice
public class GlobalExceptionHandler {
    @ExceptionHandler(IllegalArgumentException.class)
    public ResponseEntity<ErrorResponse> handleBadRequest(IllegalArgumentException e) {
        return ResponseEntity.status(HttpStatus.BAD_REQUEST)
                             .body(new ErrorResponse("400", e.getMessage()));
    }
}

핵심은 예외를 처리하지 않으면 애플리케이션의 신뢰성이 떨어진다는 것이다.


🧱 6. RDB – 관계형 데이터베이스의 구조와 설계

이번 세미나에서 가장 인상 깊었던 개념은 관계(Relation) 의 의미였다.

  • 테이블끼리 관계를 맺기 위해 PK(기본키)FK(외래키)를 사용한다.
  • 1:N 관계에서 자식 테이블(post)이 부모 테이블(user)의 ID를 FK로 참조한다.
  • 데이터의 무결성과 구조적 안정성을 보장하기 위해 정규화를 적용한다.

🔑 "DB 설계는 단순 저장소 구성 이상이다. 결국 서비스 구조를 결정하는 뼈대이다."


🔧 7. SQL – 직접 데이터를 다룰 수 있어야 한다

워크벤치를 활용한 SQL 실습을 통해 다음 쿼리들을 직접 다뤄보았다.

  • CREATE TABLE, ALTER TABLE, DROP TABLE
  • INSERT, SELECT, UPDATE, DELETE
  • JOIN을 활용한 테이블 간 관계 조회

직접 SQL을 다루면서 느낀 건, JPA를 쓰더라도 SQL의 본질은 반드시 알고 있어야 한다는 점이다.


🪄 8. JPA와 ORM의 철학

Java는 객체 지향 언어, DB는 관계형 시스템.

이 둘의 간극을 메워주는 것이 바로 ORM(Object-Relational Mapping) 이다.

  • JPA는 자바 ORM의 표준 인터페이스이다.
  • Hibernate는 JPA의 구현체이며, 스프링 부트에서는 기본으로 사용된다.
  • Spring Data JPA는 이 위에 더 많은 자동화를 얹은 추상화 도구이다.

"우리는 @Entity, @Id, @GeneratedValue 만 써도, DB와 객체 간의 변환을 거의 자동으로 처리할 수 있다."

profile
Backend Developer / Cloud Engineer

0개의 댓글