본문으로 건너뛰기

© 2026 Molayo

Dev.to헤드라인2026. 06. 06. 15:37

AI 엔지니어를 위한 FastAPI - 파트 3: 데이터베이스 연결하기

요약

FastAPI 애플리케이션에서 인메모리 저장 방식의 한계를 극복하기 위해 SQLite 데이터베이스를 연결하는 방법을 다룹니다. SQLAlchemy를 활용하여 데이터를 영구적으로 저장하고 관리하는 과정을 설명합니다.

핵심 포인트

  • 인메모리 저장 방식의 데이터 휘발성 문제 이해
  • SQLite 데이터베이스의 역할 및 특징 파악
  • SQLAlchemy를 이용한 FastAPI와 DB 연결 방법

이전 글에서는 FastAPI를 사용하여 첫 번째 CRUD API를 구축하는 방법을 살펴보았습니다. 우리의 API는 올바르게 작동했지만, 한 가지 큰 문제가 있었습니다.

우리는 데이터를 메모리(memory)에만 존재하는 Python 리스트(list) 내에 저장하고 있었습니다.

만약 여러분이 Instagram, LinkedIn 또는 ChatGPT와 같은 애플리케이션들이 서버를 재시작한 후에도 어떻게 정보를 기억하는지 궁금했다면, 정답은 간단합니다: 바로 데이터베이스(databases)입니다.

이 글에서는 SQLAlchemy를 사용하여 우리의 FastAPI 애플리케이션을 SQLite에 연결함으로써 인메모리(in-memory) 저장 문제를 해결할 것입니다.
이전 게시물을 읽지 않았다면 확인해 보세요:

AI 엔지니어를 위한 FastAPI - 파트 2: 첫 번째 CRUD API 구축하기

zeroshotanu profile

Ananya S

Ananya S

Ananya S

팔로우

Jun 1

AI 엔지니어를 위한 FastAPI - 파트 2: 첫 번째 CRUD API 구축하기

#ai #backend #fastapi #python

7 reactions댓글 댓글 추가하기

4분 읽기

이 글을 마칠 때쯤 여러분은 다음 내용을 이해하게 될 것입니다:

  • 인메모리(in-memory) 저장이 왜 문제인지
  • SQLite가 무엇인지
  • SQLAlchemy가 무엇인지
  • ORM(Object-Relational Mapping)이 어떻게 작동하는지
  • Python 클래스를 사용하여 데이터베이스 테이블을 생성하는 방법
  • 실제 데이터베이스를 사용하여 CRUD 연산을 수행하는 방법

인메모리(In-Memory) 저장의 문제점

이전에는 우리의 애플리케이션이 학생 데이터를 Python 리스트 내에 저장했습니다.

students = [
    {
        "id": 1,
...

이 방식은 CRUD 연산을 학습하는 데에는 효과적이었습니다.

하지만, 서버가 재시작될 때 어떤 일이 발생하는지 생각해 보십시오:

FastAPI 서버 중단

Python 메모리 삭제
...

이는 실제 애플리케이션 환경에서는 용납될 수 없는 일입니다.

애플리케이션이 재시작되어도 데이터가 유지될 수 있는 공간이 필요합니다.

이 지점에서 데이터베이스 (Database)가 필요하게 됩니다.

SQLite란 무엇인가요?

SQLite는 경량 관계형 데이터베이스 (Relational Database)입니다.

MySQL이나 PostgreSQL과 달리, SQLite는 별도의 데이터베이스 서버를 필요로 하지 않습니다.

대신, 모든 데이터가 단일 파일 내에 저장됩니다.

students.db

SQLite의 장점:

  • 설치가 필요 없음
  • 경량 (Lightweight)
  • 배우기 쉬움
  • 로컬 개발 (Local development)에 완벽함
  • 소규모 프로젝트에 적합함

본 아티클에서는 SQLite를 사용할 것입니다.

SQLAlchemy란 무엇인가요?

SQLAlchemy를 사용하기 전에는 개발자들이 종종 가공되지 않은 SQL 쿼리 (Raw SQL queries)를 직접 작성했습니다.

예시:

SELECT * FROM students;

SQL은 강력하지만, 모든 곳에 쿼리를 작성하는 것은 유지보수를 빠르게 어렵게 만듭니다.

SQLAlchemy는 ORM을 사용하여 이 문제를 해결합니다.

ORM이란 무엇인가요?

ORM은 객체 관계 매핑 (Object Relational Mapper)의 약자입니다.

이를 통해 Python 클래스 (Class)를 사용하여 데이터베이스 테이블 (Table)과 상호작용할 수 있습니다.

마치 번역가와 같다고 생각하면 됩니다.

데이터베이스 (Database)Python
테이블 (Table)클래스 (Class)
......

예를 들어:

데이터베이스 테이블:

students

id     name     department     cgpa
...

다음과 같이 변환됩니다:

class Student(Base):
    ...

SQL을 수동으로 작성하는 대신, Python 객체 (Object)를 가지고 작업합니다.

SQLAlchemy는 백그라운드에서 SQL을 생성합니다.

프로젝트 구조

다음과 같은 구조를 생성하세요:

project/
│
├── database.py
...

각 파일은 특정 책임을 가집니다.

database.py

책임:

  • 데이터베이스 연결 (Database connection)
  • 세션 생성 (Session creation)
  • 베이스 클래스 생성 (Base class creation)

models.py

책임:

  • 데이터베이스 테이블 (Database tables)

schemas.py

책임:

  • 요청 검증 (Request validation)
  • 응답 구조 (Response structure)

main.py

책임:

  • API 라우트 (API routes)
  • 비즈니스 로직 (Business logic)

의존성 설치

pip install sqlalchemy

아직 FastAPI를 설치하지 않았다면:

pip install fastapi uvicorn

1단계: database.py 생성하기

database.py라는 이름의 파일을 생성합니다.

from sqlalchemy import create_engine
from sqlalchemy.orm import declarative_base
from sqlalchemy.orm import sessionmaker
...

일반적으로 SQLAlchemy는 트랜잭션 모드 (transactional mode)를 사용합니다:
변경 사항을 만들면 → 세션 (session)에 스테이징(staged)되고 → commit()을 호출하여 이를 영구적으로 저장합니다.
만약 자동 커밋 (autocommit)이 활성화되어 있다면, 각 문(statement)이 즉시 커밋됩니다 (SQLite의 기본 설정과 같이).
autoflush=True (기본값)인 경우, SQLAlchemy는 쿼리를 실행하기 전에 대기 중인 변경 사항을 데이터베이스에 자동으로 플러시 (flush) 합니다.
플러시 (Flush)의 의미는 다음과 같습니다:
현재 트랜잭션 내에서 메모리 상의 변경 사항을 데이터베이스와 동기화합니다.
커밋 (commit)을 하는 것은 아닙니다 — commit()을 호출하기 전까지 변경 사항은 여전히 롤백 (rollback)이 가능합니다.

create_engine() 이해하기

engine = create_engine(...)

SQLAlchemy는 데이터베이스와 통신할 방법이 필요합니다.

Engine 객체는 FastAPI와 SQLite 사이의 가교 역할을 합니다.

우리가 다음과 같은 작업을 수행할 때마다:

  • 데이터 삽입 (insert)
  • 데이터 조회 (retrieve)
  • 데이터 수정 (update)
  • 데이터 삭제 (delete)

SQLAlchemy는 엔진을 사용하여 데이터베이스와 대화합니다.

SessionLocal 이해하기

SessionLocal = sessionmaker(...)

세션 (session)은 데이터베이스와의 대화를 나타냅니다.

은행을 방문하는 상황을 상상해 보세요:

  1. 대화 시작
  2. 거래 수행
  3. 대화 종료

데이터베이스 세션도 이와 유사하게 작동합니다.

모든 데이터베이스 작업은 세션을 통해 이루어집니다.

Base 이해하기

Base = declarative_base()

우리가 생성하는 모든 데이터베이스 모델 (model)은 Base를 상속받습니다.

SQLAlchemy는 Base를 사용하여 모든 모델을 추적하고 테이블을 자동으로 생성합니다.

데이터베이스 세션 생성하기

이전 코드 아래에 다음 함수를 추가합니다.

def get_db():

    db = SessionLocal()
...

get_db()가 필요한가요?

이 함수가 없다면, 모든 라우트 (route)에서 수동으로 세션을 생성하고 닫아야 합니다.

예시:

@app.get("/students")
def get_students():

...

이는 반복적인 작업이 됩니다.

대신, FastAPI는 우리를 대신해 세션을 자동으로 생성하고 닫아줄 수 있습니다.

나중에 우리는 다음을 사용할 것입니다:

db: Session = Depends(get_db)

FastAPI는 다음을 수행합니다:

  1. 세션 생성
  2. 라우트(route)에 세션 전달
  3. 자동으로 세션 종료

이를 의존성 주입 (Dependency Injection)이라고 합니다.

2단계: models.py 생성하기

models.py라는 이름의 파일을 생성하세요.

from sqlalchemy import Column, Integer, String, Float

from database import Base
...

모델 이해하기

__tablename__ = "students"

이 코드는 다음 이름의 테이블을 생성합니다:

students
id = Column(Integer, primary_key=True)

기본 키 (primary key)를 생성합니다.

모든 학생은 고유한 ID를 가져야 합니다.

name = Column(String)

텍스트 컬럼을 생성합니다.

학과 (department) 컬럼도 마찬가지입니다.

cgpa = Column(Float)

부동 소수점 (floating-point) 컬럼을 생성합니다.

3단계: schemas.py 생성하기

schemas.py라는 이름의 파일을 생성하세요.

from pydantic import BaseModel

class StudentCreate(BaseModel):
...

스키마 (Schemas)가 왜 필요한가요?

스키마는 우리 API가 어떤 데이터를 기대하는지 정의합니다.

지금은 스키마를 설계도 (blueprints)라고 생각하세요.

우리는 내부적으로 Pydantic을 사용하고 있습니다.

우리는 이 시리즈의 이후 전용 아티클에서 다음 내용을 살펴볼 것입니다:

  • 검증 (Validation)
  • 선택적 필드 (Optional fields)
  • 커스텀 검증기 (Custom validators)
  • 응답 모델 (Response models)

4단계: main.py 생성하기

from fastapi import FastAPI, Depends
from sqlalchemy.orm import Session

...

테이블 자동 생성하기

models.Base.metadata.create_all(bind=engine)

FastAPI가 시작될 때:

  1. SQLAlchemy가 모든 모델을 확인합니다.
  2. 누락된 테이블이 있는지 찾습니다.
  3. 자동으로 테이블을 생성합니다.

이제 우리의 Student 테이블이 SQLite 내부에 생성되었습니다.

CREATE 작업

@app.post("/student", response_model=schemas.StudentResponse)
def create_student(
    student: schemas.StudentCreate,
...

여기서 어떤 일이 일어나나요?

db.add(new_student)

객체를 세션에 추가합니다.

db.commit()

데이터를 데이터베이스에 영구적으로 저장합니다.

db.refresh(new_student)

데이터베이스로부터 객체를 다시 불러옵니다 (reloads).

데이터베이스가 ID를 자동으로 생성하기 때문에 이 작업은 유용합니다.

READ 작업

모든 학생 가져오기.

@app.get("/students")
def get_students(
    db: Session = Depends(get_db)
...

ID로 학생 가져오기.

@app.get("/student/{id}")
def get_student(
    id: int,
...

UPDATE 작업

@app.put("/student/{id}")
def update_student(
    id: int,
...

DELETE 작업

@app.delete("/student/{id}")
def delete_student(
    id: int,
...

애플리케이션 실행하기

서버 시작:

uvicorn main:app --reload

열기:

Swagger UI를 사용하여 다음 작업을 수행하세요:

  • 학생 생성 (Create)
  • 학생 조회 (Retrieve)
  • 학생 수정 (Update)
  • 학생 삭제 (Delete)

SQLite vs MySQL

좋은 소식은 SQLAlchemy를 사용하면 데이터베이스를 전환하는 것이 매우 쉽다는 점입니다.

현재 SQLite 연결:

DATABASE_URL = "sqlite:///./students.db"

MySQL 연결:

MYSQL_USER = "root"
DB_PASSWORD = "123456" # 본인의 MySQL 로그인 비밀번호를 사용하세요
MYSQL_HOST = 'localhost'
...

MySQL 드라이버 설치:

pip install pymysql

그 외의 모든 것은 거의 동일하게 유지됩니다. 데스크톱에 MySQL이 설치되어 있는지 확인하고, MySQL Workbench를 열어 데이터베이스에 연결하여 데이터베이스와 테이블을 확인하세요.

이것이 ORM (Object-Relational Mapping)을 사용하는 가장 큰 장점 중 하나입니다.

모든 것이 함께 작동하는 방식

클라이언트 요청 (Client Request)
      │
      ▼
...

사용자가 학생을 생성할 때:

  1. FastAPI가 요청을 받습니다.
  2. Pydantic이 들어오는 데이터를 검증 (Validate) 합니다.
  3. 데이터베이스 세션 (Database Session)이 생성됩니다.
  4. SQLAlchemy가 Python 객체를 SQL로 변환합니다.
  5. SQLite가 데이터를 영구적으로 저장합니다.

결론

이제 우리는 인메모리 (In-memory) 저장소를 넘어 데이터베이스 기반의 첫 번째 FastAPI 애플리케이션을 구축했습니다.
대부분의 프로덕션 AI 애플리케이션은 채팅 기록, 사용자 프로필, 에이전트 메모리 (Agent Memory), 평가 결과 또는 피드백 데이터를 저장할 때 이와 동일한 아키텍처 (Architecture)를 사용합니다.

다음 기사에서는 Pydantic을 더 자세히 살펴보고 FastAPI가 어떻게 들어오는 데이터를 자동으로 검증하는지 이해해 보겠습니다.

AI 자동 생성 콘텐츠

본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.

원문 바로가기
0

댓글

0