playreel/backend/utils/database.py
2026-09-15 16:00:54 +09:00

64 lines
2.0 KiB
Python

"""MySQL 비동기 세션
FastAPI 의존성으로 받아 씀
async def handler(session: AsyncSession = Depends(get_session)): ...
"""
from collections.abc import AsyncGenerator
from sqlalchemy.ext.asyncio import AsyncSession, async_sessionmaker, create_async_engine
from sqlalchemy.orm import DeclarativeBase
from sqlalchemy.pool import AsyncAdaptedQueuePool
from settings import settings
POOL_SIZE = 10
MAX_OVERFLOW = 10
POOL_TIMEOUT = 30
POOL_RECYCLE = 3600 # 연결을 1시간마다 새로 맺는다
class Base(DeclarativeBase):
pass
engine = create_async_engine(
settings.mysql_url,
pool_size=POOL_SIZE,
max_overflow=MAX_OVERFLOW,
poolclass=AsyncAdaptedQueuePool,
pool_timeout=POOL_TIMEOUT,
pool_recycle=POOL_RECYCLE,
pool_pre_ping=True, # 끊긴 연결을 쓰기 전에 걸러낸다
pool_reset_on_return="rollback",
echo=False,
connect_args={
"connect_timeout": 10,
"read_timeout": 30, # asyncmy에는 write_timeout이 없다
"charset": "utf8mb4",
# sql_mode는 asyncmy가 따옴표 없이 끼워 넣어 문법 오류가 나므로 여기서 같이 건다
"init_command": ("SET SESSION time_zone = '+00:00', "
"sql_mode = 'STRICT_TRANS_TABLES,NO_ZERO_DATE,NO_ZERO_IN_DATE'"),
},
)
session_factory = async_sessionmaker(bind=engine, class_=AsyncSession,
expire_on_commit=False, autoflush=False)
async def get_session() -> AsyncGenerator[AsyncSession, None]:
async with session_factory() as session:
try:
yield session
except Exception:
await session.rollback()
raise
async def create_missing_tables() -> None:
"""없는 테이블만 만든다. 컬럼이 바뀐 기존 테이블은 건드리지 않는다"""
async with engine.begin() as connection:
await connection.run_sync(Base.metadata.create_all)
async def close_engine() -> None:
await engine.dispose()