"""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()