AI 엔지니어를 위한 FastAPI - 3부: 데이터베이스 연결

발행: (2026년 6월 6일 PM 03:27 GMT+9)
9 분 소요
원문: Dev.to

Source: Dev.to

이전 글에서는 FastAPI를 사용해 첫 번째 CRUD API를 만드는 과정을 살펴보았습니다. API는 정상적으로 동작했지만, 한 가지 큰 문제가 있었습니다.

우리는 데이터를 메모리 안에 존재하는 Python 리스트에 저장하고 있었습니다.

인스타그램, LinkedIn, 혹은 ChatGPT와 같은 애플리케이션이 서버를 재시작한 뒤에도 정보를 기억하는 이유가 궁금하다면, 답은 간단합니다: 데이터베이스.

이번 글에서는 SQLite와 SQLAlchemy를 이용해 FastAPI 애플리케이션을 데이터베이스에 연결함으로써 메모리 저장 문제를 해결합니다.

이전 글을 아직 읽지 않으셨다면, 먼저 확인해 보세요:

이 글을 다 읽고 나면 다음을 이해하게 됩니다:

  • 메모리 저장이 왜 문제인지
  • SQLite가 무엇인지
  • SQLAlchemy가 무엇인지
  • ORM이 어떻게 동작하는지
  • Python 클래스로 데이터베이스 테이블을 만드는 방법
  • 실제 데이터베이스를 이용해 CRUD 작업을 수행하는 방법

In-Memory Storage의 문제점

이전에는 애플리케이션이 학생 정보를 Python 리스트에 저장했습니다.

students = [
    {
        "id": 1,
        "name": "Ananya",
        "department": "CSE",
        "cgpa": 8.9
    }
]

이는 CRUD 연산을 배우기에 충분했습니다.

하지만 서버가 재시작되면 어떻게 될까요?

FastAPI 서버 중지

Python 메모리 초기화

모든 학생 데이터 손실

실제 서비스에서는 받아들일 수 없는 상황입니다.

애플리케이션이 재시작돼도 데이터를 유지할 수 있는 장소가 필요합니다.

바로 데이터베이스가 그 역할을 합니다.

SQLite란?

SQLite는 가벼운 관계형 데이터베이스입니다.

MySQL이나 PostgreSQL과 달리 별도의 데이터베이스 서버가 필요하지 않으며, 모든 데이터가 하나의 파일에 저장됩니다.

students.db

SQLite의 장점

  • 설치가 필요 없음
  • 가벼움
  • 배우기 쉬움
  • 로컬 개발에 최적
  • 작은 프로젝트에 적합

이번 글에서는 SQLite를 사용합니다.

SQLAlchemy란?

SQLAlchemy가 등장하기 전에는 개발자들이 직접 순수 SQL 쿼리를 작성했습니다.

예시:

SELECT * FROM students;

SQL은 강력하지만, 코드 곳곳에 쿼리를 흩뿌리면 유지보수가 어려워집니다.

SQLAlchemy는 ORM을 통해 이 문제를 해결합니다.

ORM이란?

ORM은 Object Relational Mapper의 약자입니다.

데이터베이스 테이블을 Python 클래스와 매핑해, 객체 지향 방식으로 데이터베이스를 다룰 수 있게 해줍니다. 일종의 번역가 역할을 합니다.

Database   ↔   Python
Table      ↔   Class
Row        ↔   Object
Column     ↔   Attribute

예시:

데이터베이스 테이블

students

id   name    department   cgpa
1    Ananya  CSE          8.9

Python 클래스

class Student(Base):
    ...

SQL을 직접 작성하는 대신 Python 객체를 다루게 되며, SQLAlchemy가 내부적으로 SQL을 생성합니다.

프로젝트 구조

다음과 같은 디렉터리 구조를 만든다:

project/

├── database.py
├── models.py
├── schemas.py
├── main.py
└── students.db

각 파일은 다음과 같은 역할을 담당합니다.

  • database.py: 데이터베이스 연결, 세션 생성, Base 클래스 정의
  • models.py: 데이터베이스 테이블 정의
  • schemas.py: 요청 검증 및 응답 구조 정의
  • main.py: API 라우트와 비즈니스 로직
  • students.db: 실제 SQLite 파일

의존성 설치

pip install sqlalchemy

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

pip install fastapi uvicorn

Step 1: database.py 만들기

database.py 파일을 생성하고 다음 코드를 넣는다.

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

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

engine = create_engine(
    DATABASE_URL,
    connect_args={"check_same_thread": False} # 스레드 간에 동일한 연결을 사용할 수 있게 함
)

SessionLocal = sessionmaker(
    autocommit=False, 
    autoflush=False,
    bind=engine
)

Base = declarative_base()

보통 SQLAlchemy는 트랜잭션 모드로 동작합니다.
변경 사항을 세션에 쌓아두었다가 commit()을 호출하면 영구 저장됩니다.

autocommit이 활성화되면 각 문장이 즉시 커밋됩니다(예: SQLite 기본 동작).

autoflush=True(기본값)일 경우, 쿼리를 실행하기 전에 보류 중인 변경 사항을 자동으로 데이터베이스에 플러시합니다.

플러시란: 현재 트랜잭션 안에서 메모리상의 변경을 데이터베이스와 동기화하는 작업이며, 아직 커밋되지 않아 롤백이 가능합니다.

create_engine() 이해하기

engine = create_engine(...)

SQLAlchemy가 데이터베이스와 통신하기 위해 엔진 객체가 필요합니다. 엔진은 FastAPI와 SQLite 사이의 다리 역할을 합니다. 삽입, 조회, 수정, 삭제 등 모든 데이터베이스 작업이 엔진을 통해 이루어집니다.

SessionLocal 이해하기

SessionLocal = sessionmaker(...)

세션은 데이터베이스와의 대화를 의미합니다. 은행에 방문해 대화를 시작하고, 여러 거래를 수행한 뒤 대화를 종료하는 것과 비슷합니다. 모든 데이터베이스 작업은 세션을 통해 이루어집니다.

Base 이해하기

Base = declarative_base()

우리가 정의하는 모든 모델은 Base를 상속받습니다. SQLAlchemy는 Base를 통해 모델들을 추적하고 테이블을 자동으로 생성합니다.

데이터베이스 세션 만들기

앞의 코드 아래에 다음 함수를 추가한다.

def get_db():
    db = SessionLocal()
    try:
        yield db
    finally:
        db.close()

get_db()가 필요한가?

이 함수를 사용하지 않으면 각 라우트마다 세션을 직접 만들고 닫아야 합니다.

예시:

@app.get("/students")
def get_students():
    db = SessionLocal()
    # 데이터베이스 작업
    db.close()

코드가 중복됩니다. FastAPI는 Depends(get_db)를 통해 세션을 자동으로 생성·제공·종료해 줍니다. 이를 Dependency Injection이라고 합니다.

Step 2: models.py 만들기

models.py 파일을 생성하고 다음 코드를 넣는다.

from sqlalchemy import Column, Integer, String, Float

from database import Base

class Student(Base):
    __tablename__ = "students"

    id = Column(Integer, primary_key=True, index=True)
    name = Column(String)
    department = Column(String)
    cgpa = Column(Float)

모델 이해하기

__tablename__ = "students"

위 코드는 students라는 이름의 테이블을 생성합니다.

id = Column(Integer, primary_key=True)

기본 키를 정의합니다. 각 학생은 고유한 ID를 가져야 합니다.

name = Column(String)

텍스트 컬럼을 생성합니다. department도 동일하게 문자열 컬럼입니다.

cgpa = Column(Float)
0 조회
Back to Blog

관련 글

더 보기 »

모바일 한여름 열풍

!Cover image for Mobile Midsommer Madnesshttps://media2.dev.to/dynamic/image/width=1000,height=420,fit=cover,gravity=auto,format=auto/https%3A%2F%2Fdev-to-uploa...