FastAPI/데이터베이스

데이터베이스 연결

hyunai 2026. 6. 4. 22:27

라이브러리 다운로드

pip install sqlalchemy
pip install pymysql

 python과 mysql을 연동할 때 사용되는 드라이버

pip install cryptography

pyMySQL을 통해 MySQL에 접속할 때 인증이나 암호 관련된 처리를 해주는 라이브러리

데이터베이스 연결

# 라이브러리 import
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker

# root 계정의 todos라는 비밀번호를 이용한다. 포트는 이렇게 사용하고 todos 데이터베이스를 사용한다. 라는 의미
DATABASE_URL = "mysql+pymysql://root:todos@127.0.0.1:3306/todos"

# 어느 SQL Alchemy를 이용해서 데이터베이스에 접속하기 위해서는 먼저 engine이라는 객체를 만들어야된다.
# echo = True : SQL Alchemy에 의해서 여러가지 쿼리가 대신 처리되는데 그 쿼리가 대신 처리될 때 어떤 sql이 사용됐는지 사용되는 시점에 사용되는 SQL을 출력해주는 옵션
engine = create_engine(DATABASE_URL, echo=True)
# Session이란 것을 생성해서 인스턴스를 통해 데이터베이스와 통신
# 자동 커밋, 플러쉬를 하지않고 수동으로 하겠다.
# bind = engine : 전달한 이 데이터베이스 UI를 통해서 어떤 엔진이라는 기체가 생성이 되고 그 엔진을 사용해서 실제로 Session을 만들 수 있게 된다.
SessionFactory = sessionmaker(autocommit = False, autoflush = False, bind = engine)

SQLAlchemy 전체 구조 이해하기

SQLAlchemy 전체 구조

내 Python 코드
      ↓
  SQLAlchemy        ← "번역가" 역할
      ↓
   Engine           ← "자동차 엔진" 역할 (DB 연결 담당)
      ↓
  Connection Pool   ← "연결 대기실" 역할
      ↓
   Session          ← "창구 직원" 역할 (실제 대화 담당)
      ↓
  MySQL DB          ← 실제 데이터 저장소

1. SQLAlchemy가 뭔지

SQLAlchemy 역할 비유

SQLAlchemy 없을 때
─────────────────────────────
Python 코드
    ↓
직접 SQL 작성
"SELECT * FROM todo WHERE id = 1"
    ↓
MySQL

SQLAlchemy 있을 때
─────────────────────────────
Python 코드
    ↓
Python으로 작성
session.get(ToDo, 1)
    ↓
SQLAlchemy가 SQL로 자동 번역
"SELECT * FROM todo WHERE id = 1"
    ↓
MySQL

💡 SQLAlchemy = Python 코드를 SQL로 자동 번역해주는 번역가


2. Engine이 뭔지

Engine 비유

DATABASE_URL = "mysql+pymysql://root:todos@127.0.0.1:3306/todos"
                  ↑              ↑     ↑       ↑        ↑
               어떤 DB        계정  비번    주소     DB이름
               (MySQL)

Engine = 이 정보를 갖고 DB와 연결하는 방법을 알고 있는 객체

자동차로 비유하면:

Engine 비유

비유 실제
자동차 엔진 Engine 객체
연료 DATABASE_URL (어디에 어떻게 연결할지)
시동 걸기 create_engine()
실제 주행 Session이 담당

Engine 역할

# Engine은 실제로 연결을 맺지는 않아요
# "나는 이 DB에 이렇게 연결하는 방법을 알고 있어" 만 기억해두는 것
engine = create_engine(DATABASE_URL, echo=True)
#                                    ↑
#                      SQL 실행될 때마다 콘솔에 출력해줌
#                      (개발할 때 디버깅용으로 씀)

# echo=True 덕분에 이런 로그가 콘솔에 찍히는 거예요
# INFO sqlalchemy.engine.Engine SELECT todo.id, todo.contents...

3. Connection Pool이 뭔지

Connection Pool 비유

Connection Pool = 연결 대기실

DB 연결을 미리 여러 개 만들어서 대기시켜 놓음
──────────────────────────────────────────
[연결1 대기중] [연결2 대기중] [연결3 대기중]

요청 들어오면
──────────────────────────────────────────
[연결1 사용중] [연결2 대기중] [연결3 대기중]
  ↑
GET /todos 요청이 이 연결 가져다 씀

요청 끝나면
──────────────────────────────────────────
[연결1 반납!] [연결2 대기중] [연결3 대기중]

💡 매번 연결을 새로 만들면 느리니까, 미리 만들어 놓고 돌려쓰는 것


4. Session이 뭔지

Session 비유

은행으로 비유하면:

Engine      = 은행 건물 (DB와 연결하는 방법 알고 있음)
Connection  = 은행 창구 (실제 연결)
Session     = 창구 직원 (실제로 대화하는 사람)

나(Python 코드)
    ↓
Session(창구 직원)한테 요청
"todo 목록 조회해줘"
    ↓
Session이 SQL로 번역해서 DB에 전달
"SELECT * FROM todo"
    ↓
결과 받아서 나한테 전달

Session이 하는 일들

session = SessionFactory()

# 1. 조회
todos = session.scalars(select(ToDo))

# 2. 추가
new_todo = ToDo(contents="새 할일", is_done=False)
session.add(new_todo)
session.commit()  # ← 실제 DB에 반영 (수동 커밋)

# 3. 수정
todo = session.get(ToDo, 1)
todo.is_done = True
session.commit()  # ← 수동 커밋

# 4. 삭제
session.delete(todo)
session.commit()  # ← 수동 커밋

# 5. 닫기
session.close()  # ← Connection Pool에 연결 반납

5. SessionFactory 설정 완전 분해

SessionFactory 설정 의미

SessionFactory = sessionmaker(
    autocommit=False,   # 자동으로 commit 하지 마
                        # → 내가 직접 session.commit() 해야 DB에 반영됨
                        # → 실수로 잘못된 데이터 저장 방지

    autoflush=False,    # 자동으로 flush 하지 마
                        # → flush = "변경사항을 DB에 예고편으로 보내기"
                        # → 내가 원할 때만 DB에 보내겠다

    bind=engine         # 이 engine을 사용해서 연결해
                        # → 어떤 DB에 연결할지 알려주는 것
)

autocommit 과 autoflush 차이

설정  False일 때 True일 때
autocommit session.commit() 직접 호출해야 DB 반영 자동으로 즉시 반영
autoflush 내가 원할 때만 DB에 예고편 전송 쿼리 전에 자동으로 예고편 전송

6. 전체 흐름 한눈에 보기

실제 API 요청 전체 흐름

GET /todos 요청
      ↓
Depends(get_db) 실행
      ↓
SessionFactory()     ← Connection Pool에서 연결 하나 가져옴
      ↓
session 생성         ← 이 session으로 DB와 대화 시작
      ↓
session.scalars(select(ToDo))
      ↓
Engine이 SQL로 번역
"SELECT todo.id, todo.contents, todo.is_done FROM todo"
      ↓
MySQL DB에서 결과 반환
      ↓
Python 객체(ToDo)로 변환
      ↓
JSON 응답 반환
      ↓
session.close()      ← Connection Pool에 연결 반납

💡 핵심 요약:
SQLAlchemy = Python ↔ SQL 번역가
Engine = DB 연결 방법을 알고 있는 엔진
Connection Pool = 연결을 미리 만들어 놓는 대기실
Session = 실제로 DB와 대화하는 창구 직원
autocommit=False = 내가 직접 commit 해야 DB에 반영됨

파이썬 콘솔에 입력

from database.connection import SessionFactory
  • 먼저 SessionFactory를 import
session = SessionFactory()
  • session 객체 먼저 생성
from sqlalchemy import select
  • select 쿼리를 사용하기 위해 sqlalchemy import
session.scalar(select(1))

  • select(1)을 출력하는 즉 1을 출력하는 쿼리를 데이터베이스에 날려보기
  • 실제로 어떤 데이터가 의미 있는 데이터가 출력이 되진 않지만 이 세션을 통해서 이렇게 쿼리를 날리는 것만으로도 데이터베이스에 연결됐는지 확인할 수 있다.
  • 이런 로그들이 나타나는 경우는 앞서 echo옵션을 줬기 때문이다.
    • 그래서 로그를 확인을 해보면 데이터베이스에 연결을 해서 이런식으로 SELECT 쿼리가 발생했다는 것을 알 수 있다.
  • 정상적으로 처리가 됐기 때문에 1이 출력된다.
  • 만약 도커가 정상적으로 돌고 있지 않거나 todos 데이터베이스가 잘 생성되지 않았다면 쿼리를 날려도 아무것도 출력이 되지 않는다.

'FastAPI > 데이터베이스' 카테고리의 다른 글

ORM 적용 - GET 전체 조회 API / Python - Generator  (0) 2026.06.14
ORM 모델링  (1) 2026.06.09
DDL - Create Table  (0) 2026.06.04
MySQL 컨테이너 실행  (0) 2026.05.19
sqlalchemy  (0) 2026.05.19