# Day19 My SQL + FastAPI 연동해서 사용하기

D0-$ANG ₩0N·2025년 12월 3일
post-thumbnail

1. MySQL 간단설명

MySQL은 가장 널리 사용되고 있는 관계형 데이터베이스 관리 시스템(RDBMS, Relational DataBase Management System)이다.

MySQL 안에는 DBMS(데이터베이스 관리 시스템)이 있다.
DBMS 내부에는 여러 데이터베이스 객체(DB) 가 존재.
기본 포트는 3306.

2. SQL과 ORM 설명

SQL
문자열에 SQL을 직접 넣어서 실행하는 방식

EX)
SELECT name, price FROM menu;

실행 결과는 2차원 배열(레코드셋) 로 받아서 코드로 처리함.

ORM(Object Relational Mapping) 개념

SQL을 직접 쓰지 않고 클래스(객체) 로 DB 테이블을 표현.

EX)

class Menu:
name: str
price: int

이를 ORM이 SQL로 자동 변환해줌.

ORM 장점

SQL 지식이 부족해도 개발 가능 유지보수, 확장성 높음

ORM 한계

복잡한 JOIN / GROUP BY 등 고급 SQL은 어려움.

요즘 백엔드는 "FastAPI + React" 구조가 대세

ORM을 사용하는 시대이지만 SQL 기본기는 필요함

INSERT / SELECT / UPDATE / DELETE 기본 문법 꼭 알아야 함

특히 JOIN, PK/FK 이해는 필수

FastAPI는 JSON API + ORM으로 DB와 연결

Workbench에서 테이블 확인/조작 능력 필수

DB와 서버 연동 구조를 이해해야 진짜 개발자

3.Primary Key(프라이머리 키) 기본 개념

프라이머리 키는 테이블에서 식별자 역할을 하는 컬럼이다.

특징 3가지

Unique(고유값) — 절대 중복될 수 없다.

Not Null(널 불가) — 값이 반드시 있어야 한다.

1개 또는 복합키 가능 — 여러 컬럼을 묶어서 PK로 만들 수 있음.

한국사례: PK로 주민번호를 쓰지 않는 이유

1990년 이전 출생자는 중복 주민번호 발생 사례 존재

현재는 정부 시스템이 생성하여 중복 거의 없음

PK는 변경 가능성이 없어야 하는데, 주민번호 변경 발생 가능 → 적절하지 않음

그래서 일반적으로 PK는?

id 컬럼

타입: INT

옵션: PRIMARY KEY, AUTO_INCREMENT, UNSIGNED

4.DDL / DML 개념

SQL은 크게 두 종류로 나뉜다.

DDL (Data Definition Language) — 구조 정의

CREATE

ALTER

DROP

테이블 구조나 스키마(메타 데이터)를 다룸
→ 예: CREATE TABLE ...

데이터(Data): 실제 저장되는 값 (이름, 가격 등)

메타데이터(Metadata): 데이터 구조 정보
예: 테이블의 컬럼 정보, 타입, 길이

스키마(Schema): 테이블 구조에 대한 전체 설계도

DML (Data Manipulation Language) — 데이터 조작

INSERT

SELECT

UPDATE

DELETE

실제 데이터 레코드를 다룸

5. 테이블 & 데이터베이스 생성 흐름

데이터베이스 생성

CREATE DATABASE kakao3;

사용 선언

USE kakao3;

테이블 생성 예 (menu)

CREATE TABLE menu (
    id INT PRIMARY KEY AUTO_INCREMENT,
    name VARCHAR(20) NOT NULL,
    price INT NOT NULL
);

VARCHAR(n) : 가변 길이 문자열

CHAR(n) : 고정 길이 문자열**

문자열은 반드시 작은따옴표 ' ' 사용

6. INSERT 문법 3가지

전체 컬럼 순서대로 입력 (기본형)

INSERT INTO menu VALUES (1, '라떼', 3000);

컬럼 이름을 지정해서 입력

INSERT INTO menu (name, price)
VALUES ('라떼', 3000);

(autoincrement라면 id를 생략할 수 있음)

SET 스타일 (MySQL/MariaDB에서만)

INSERT INTO menu SET
name='라떼', price=3000;

7. SELECT 기본

모든 컬럼 조회

SELECT * FROM menu;

특정 컬럼만 조회

SELECT name, price FROM menu;

조건 조회 (WHERE)

SELECT * FROM menu WHERE price >= 3500;

8. 비교 연산자 / 논리 연산자

연산 의미
= 같다
!= 또는 <> 같지 않다

>, <, >=, <= 숫자 비교

AND 그리고

OR 또는

9.정렬 (ORDER BY)

SELECT * FROM menu ORDER BY price ASC;

오름차순

SELECT * FROM menu ORDER BY price DESC;

내림차순

10. DELETE 문

반드시 WHERE 절 있어야 함
안 쓰면 전부 삭제됨.

DELETE FROM menu WHERE id = 1;

11. UPDATE 문

UPDATE menu SET price = 6000 WHERE name = '유니짜장';

12. AUTO_INCREMENT 설정하는 법

이미 생성된 테이블에 적용

ALTER TABLE menu
MODIFY id INT PRIMARY KEY AUTO_INCREMENT;

장점:id 값을 신경 안 써도 됨
중간 값이 삭제되어도 재사용하지 않음 (PK 안정성 ↑)

13. ORM(SQLAlchemy)에서 CRUD 작동 방식

✔ CREATE (추가)

menu = Menu(name="우동", price=6000)
db.add(menu)
db.commit()
db.refresh(menu)

READ (조회)

db.query(Menu).all()

조건 조회

db.query(Menu).filter(Menu.price > 3000).all()

ORDER BY

db.query(Menu).order_by(Menu.price).all()

과제

1.코드

database.py

from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker, declarative_base
from dotenv import load_dotenv
import os

load_dotenv() 

DATABASE_URL = "mysql+pymysql://root:00000000@localhost:3306/kakao3"


engine = create_engine(DATABASE_URL)

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

Base = declarative_base()

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

models.py


from database import Base
from sqlalchemy import Column, Integer, String

class Menu(Base):
    __tablename__ = "menu"

    id = Column(Integer, primary_key=True, index=True)
    name = Column(String(50), nullable=False)
    price = Column(Integer, nullable=False)

main.py

from fastapi import FastAPI, Depends
from sqlalchemy.orm import Session
from database import engine, Base, get_db
from models import Menu


Base.metadata.create_all(bind=engine)

app = FastAPI()

@app.get("/")
async def home():
    return {"message": "Hello World"}
@app.get("/menu")
async def get_menu(db: Session = Depends(get_db)):
    menu = db.query(Menu).all()
    return menu


@app.post("/menu/{name}/{price}")
async def addMenu(name: str, price: int, db: Session = Depends(get_db)):
    menu = Menu(name=name, price=price)
    db.add(menu)
    db.commit()
    db.refresh(menu)
    return menu

2. 화면


메뉴추가하면


http://127.0.0.1:8000/menu 들어갔을때 추가됨

3. 코드분석

1. database.py — 데이터베이스 연결 & 세션 관리

DATABASE_URL

MySQL에 접속하기 위한 URL.
mysql+pymysql://user:password@host:port/dbname 형식이며 여기서는 kakao3 데이터베이스를 사용한다.

engine

SQLAlchemy가 실제 DB와 통신하기 위한 핵심 객체.

연결 풀 관리

SQL 실행

ORM과 DB를 연결하는 다리 역할

SessionLocal

트랜잭션 단위 작업을 위한 DB 세션 생성기.
autocommit=False 덕분에 원하는 시점에 db.commit()을 명시적으로 호출해야 한다.

이 설정은 의도치 않은 DB 변경을 막기 때문에 프로덕션 기본 설정이다.

Base = declarative_base()

모든 모델 클래스(Menu 등)의 부모 클래스.
모델을 선언하려면 이 Base를 반드시 상속해야 SQLAlchemy가 테이블로 인식한다.

get_db() — FastAPI 의존성 주입(DI)용

FastAPI에서 DB 세션을 관리하는 표준 패턴.

FastAPI는 이 함수를 호출해

요청 시작 → 세션 열고

요청 끝 → 세션 자동 종료

하는 과정을 깔끔하게 처리할 수 있다.

2.models.py

Menu 클래스 = menu 테이블

ORM에서는 클래스 = 테이블
속성 = 컬럼

컬럼 설명
컬럼 타입 설명
id Integer, PK 기본키, 자동 증가
name String(50) 메뉴 이름
price Integer 가격

SQLAlchemy는 이 클래스를 기반으로 실제 MySQL 테이블 구조를 자동으로 생성한다.

3. main.py
from fastapi import FastAPI, Depends
from sqlalchemy.orm import Session
from database import engine, Base, get_db
from models import Menu

Base.metadata.create_all(bind=engine)

app = FastAPI()

Base.metadata.create_all(bind=engine)
모델(Menu) 정의를 바탕으로 DB에 테이블을 자동 생성한다.

3-1. 기본 라우트

@app.get("/")
async def home():
    return {"message": "Hello World"}

잘됐는지 확인해볼려고 만든 기본 엔드포인트.

3-2. 메뉴 전체 조회 API

@app.get("/menu")
async def get_menu(db: Session = Depends(get_db)):
    menu = db.query(Menu).all()
    return menu

db: Session = Depends(get_db)
→ 요청마다 새로운 DB 세션을 자동으로 주입받는다.

db.query(Menu).all()
SELECT * FROM menu 실행

ORM 객체를 JSON 형태로 반환

FastAPI가 자동으로 ORM 객체를 dict로 바꿔준다.

3-3. 메뉴 추가 API

@app.post("/menu/{name}/{price}")
async def addMenu(name: str, price: int, db: Session = Depends(get_db)):
    menu = Menu(name=name, price=price)
    db.add(menu)
    db.commit()
    db.refresh(menu)
    return menu
profile
Change Up

0개의 댓글