smarteye-backend / app /database.py
AkJeond's picture
fix: Dockerfile LOCALE ์„ค์ • ๋ฐ database.py ์ธ์ฝ”๋”ฉ ๊ฐ•ํ™” (ํ•œ๊ธ€ ๋ฌธ์ œ ์™„์ „ ํ•ด๊ฒฐ)
d511249
"""
SmartEyeSsen Backend - Database Connection Configuration
=========================================================
SQLAlchemy ์—”์ง„, ์„ธ์…˜ ๊ด€๋ฆฌ ๋ฐ Base ํด๋ž˜์Šค ์ •์˜
์ฃผ์š” ๊ธฐ๋Šฅ:
- MySQL ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์—ฐ๊ฒฐ ์„ค์ •
- ์„ธ์…˜ ์ƒ์„ฑ ๋ฐ ์˜์กด์„ฑ ์ฃผ์ž…
- ๋น„๋™๊ธฐ ์ปจํ…์ŠคํŠธ ๋งค๋‹ˆ์ € ์ง€์›
"""
from sqlalchemy import create_engine, event, text
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker, Session
from typing import Generator
import os
from dotenv import load_dotenv
# ============================================================================
# ํ™˜๊ฒฝ ๋ณ€์ˆ˜ ๋กœ๋“œ
# ============================================================================
from pathlib import Path
# .env ํŒŒ์ผ ๊ฒฝ๋กœ ๋ช…์‹œ์ ์œผ๋กœ ์ง€์ •
env_path = Path(__file__).parent.parent / '.env'
load_dotenv(dotenv_path=env_path, override=True)
# ============================================================================
# ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์„ค์ •
# ============================================================================
DB_HOST = os.getenv("DB_HOST", "localhost")
DB_PORT = os.getenv("DB_PORT", "3306")
DB_USER = os.getenv("DB_USER", "root")
DB_PASSWORD = os.getenv("DB_PASSWORD", "root") # โ† ๊ธฐ๋ณธ๊ฐ’์„ "root"๋กœ ๋ณ€๊ฒฝ
DB_NAME = os.getenv("DB_NAME", "smarteyessen_db")
# ๋””๋ฒ„๊ทธ ์ถœ๋ ฅ (๊ฐœ๋ฐœ ์ค‘์—๋งŒ ์‚ฌ์šฉ)
print(f"๐Ÿ” DB Config: {DB_USER}@{DB_HOST}:{DB_PORT}/{DB_NAME}")
print(f"๐Ÿ” Password loaded: {'Yes' if DB_PASSWORD else 'No'}")
# MySQL ์—ฐ๊ฒฐ URL ์ƒ์„ฑ
# pymysql ๋“œ๋ผ์ด๋ฒ„ ์‚ฌ์šฉ, charset=utf8mb4 ์„ค์ •
SQLALCHEMY_DATABASE_URL = (
f"mysql+pymysql://{DB_USER}:{DB_PASSWORD}@{DB_HOST}:{DB_PORT}/{DB_NAME}"
f"?charset=utf8mb4&use_unicode=1"
)
# ============================================================================
# SQLAlchemy Engine ์ƒ์„ฑ
# ============================================================================
engine = create_engine(
SQLALCHEMY_DATABASE_URL,
# ์—ฐ๊ฒฐ ํ’€ ์„ค์ •
pool_size=10, # ๊ธฐ๋ณธ ์—ฐ๊ฒฐ ์ˆ˜
max_overflow=20, # ์ถ”๊ฐ€ ๊ฐ€๋Šฅํ•œ ์ตœ๋Œ€ ์—ฐ๊ฒฐ ์ˆ˜
pool_pre_ping=True, # ์—ฐ๊ฒฐ ์œ ํšจ์„ฑ ์ž๋™ ์ฒดํฌ
pool_recycle=3600, # 1์‹œ๊ฐ„๋งˆ๋‹ค ์—ฐ๊ฒฐ ์žฌ์ƒ์„ฑ
echo=False, # SQL ๋กœ๊ทธ ์ถœ๋ ฅ (๊ฐœ๋ฐœ ์‹œ True๋กœ ๋ณ€๊ฒฝ ๊ฐ€๋Šฅ)
# PyMySQL ๋“œ๋ผ์ด๋ฒ„์— ์ง์ ‘ charset ์ „๋‹ฌ (ํ•œ๊ธ€ ์ธ์ฝ”๋”ฉ ๋ฌธ์ œ ํ•ด๊ฒฐ)
connect_args={
"charset": "utf8mb4",
"use_unicode": True,
"init_command": "SET NAMES utf8mb4 COLLATE utf8mb4_unicode_ci"
}
)
# ============================================================================
# SessionLocal ํด๋ž˜์Šค ์ƒ์„ฑ
# ============================================================================
SessionLocal = sessionmaker(
autocommit=False, # ์ž๋™ ์ปค๋ฐ‹ ๋น„ํ™œ์„ฑํ™”
autoflush=False, # ์ž๋™ ํ”Œ๋Ÿฌ์‹œ ๋น„ํ™œ์„ฑํ™”
bind=engine,
)
# ============================================================================
# Base ํด๋ž˜์Šค ์ •์˜
# ============================================================================
Base = declarative_base()
# ============================================================================
# ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์„ธ์…˜ ์˜์กด์„ฑ ํ•จ์ˆ˜
# ============================================================================
def get_db() -> Generator[Session, None, None]:
"""
FastAPI ์˜์กด์„ฑ ์ฃผ์ž…์šฉ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์„ธ์…˜ ์ƒ์„ฑ
์‚ฌ์šฉ ์˜ˆ์‹œ:
```python
@app.get("/users")
def read_users(db: Session = Depends(get_db)):
users = db.query(User).all()
return users
```
Yields:
Session: SQLAlchemy ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์„ธ์…˜
"""
db = SessionLocal()
try:
yield db
finally:
db.close()
# ============================================================================
# ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์ดˆ๊ธฐํ™” ํ•จ์ˆ˜
# ============================================================================
def init_db():
"""
๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ํ…Œ์ด๋ธ” ์ƒ์„ฑ (๊ฐœ๋ฐœ ํ™˜๊ฒฝ์šฉ)
์ฃผ์˜: ์šด์˜ ํ™˜๊ฒฝ์—์„œ๋Š” Alembic ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ ์‚ฌ์šฉ ๊ถŒ์žฅ
"""
# models.py importํ•˜์—ฌ ํ…Œ์ด๋ธ” ์ •์˜ ๋กœ๋“œ
from . import models # ๋ชจ๋“  ๋ชจ๋ธ ํด๋ž˜์Šค๋ฅผ Base.metadata์— ๋“ฑ๋ก
# models.py์—์„œ ์ •์˜ํ•œ ๋ชจ๋“  ํ…Œ์ด๋ธ” ์ƒ์„ฑ
Base.metadata.create_all(bind=engine)
print("โœ… Database tables created successfully!")
def drop_all_tables():
"""
๋ชจ๋“  ํ…Œ์ด๋ธ” ์‚ญ์ œ (๊ฐœ๋ฐœ/ํ…Œ์ŠคํŠธ ํ™˜๊ฒฝ์šฉ)
โš ๏ธ ์ฃผ์˜: ๋ชจ๋“  ๋ฐ์ดํ„ฐ๊ฐ€ ์‚ญ์ œ๋ฉ๋‹ˆ๋‹ค!
"""
# models.py importํ•˜์—ฌ ํ…Œ์ด๋ธ” ์ •์˜ ๋กœ๋“œ
from . import models # ๋ชจ๋“  ๋ชจ๋ธ ํด๋ž˜์Šค๋ฅผ Base.metadata์— ๋“ฑ๋ก
Base.metadata.drop_all(bind=engine)
print("โš ๏ธ All database tables dropped!")
# ============================================================================
# ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์—ฐ๊ฒฐ ํ…Œ์ŠคํŠธ ํ•จ์ˆ˜
# ============================================================================
def test_connection():
"""
๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์—ฐ๊ฒฐ ํ…Œ์ŠคํŠธ
Returns:
bool: ์—ฐ๊ฒฐ ์„ฑ๊ณต ์—ฌ๋ถ€
"""
try:
# ๊ฐ„๋‹จํ•œ ์ฟผ๋ฆฌ ์‹คํ–‰ํ•˜์—ฌ ์—ฐ๊ฒฐ ํ™•์ธ
with engine.connect() as connection:
result = connection.execute(text("SELECT 1"))
print("โœ… Database connection successful!")
return True
except Exception as e:
print(f"โŒ Database connection failed: {e}")
return False
# ============================================================================
# SQLAlchemy Event Listeners (์„ ํƒ์‚ฌํ•ญ)
# ============================================================================
@event.listens_for(engine, "connect")
def set_sqlite_pragma(dbapi_conn, connection_record):
"""
MySQL ์—ฐ๊ฒฐ ์‹œ ์ถ”๊ฐ€ ์„ค์ •
- ํƒ€์ž„์กด ์„ค์ •
- ๋ฌธ์ž์…‹ ํ™•์ธ
"""
cursor = dbapi_conn.cursor()
# UTF-8 ๋ฌธ์ž์…‹ ๊ฐ•์ œ ์„ค์ •
cursor.execute("SET NAMES utf8mb4")
cursor.execute("SET CHARACTER SET utf8mb4")
cursor.execute("SET character_set_connection=utf8mb4")
cursor.close()
# ============================================================================
# ๊ฐœ๋ฐœ์šฉ ์œ ํ‹ธ๋ฆฌํ‹ฐ
# ============================================================================
if __name__ == "__main__":
"""
์ง์ ‘ ์‹คํ–‰ ์‹œ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์—ฐ๊ฒฐ ํ…Œ์ŠคํŠธ
์‹คํ–‰ ๋ฐฉ๋ฒ•:
```bash
python app/database.py
```
"""
print("=" * 60)
print("SmartEyeSsen Database Connection Test")
print("=" * 60)
print(f"Database URL: {SQLALCHEMY_DATABASE_URL.replace(DB_PASSWORD, '***')}")
print("-" * 60)
test_connection()
print("=" * 60)