""" config_db.py 데이터베이스 연결 설정 (MariaDB + aiomysql) 비동기 연결 풀 생성 및 관리. """ from collections.abc import Callable from typing import Any, Optional import aiomysql from .config_system import ( DB_HOST, DB_NAME, DB_PASSWORD, DB_POOL_MAX, DB_POOL_MIN, DB_PORT, DB_USER, ) # 글로벌 DB 풀 (앱 시작/종료 시 관리) db_pool: Optional[aiomysql.Pool] = None async def init_db_pool() -> aiomysql.Pool: """MariaDB 연결 풀 초기화""" global db_pool db_pool = await aiomysql.create_pool( host=DB_HOST, port=DB_PORT, db=DB_NAME, user=DB_USER, password=DB_PASSWORD, minsize=DB_POOL_MIN, maxsize=DB_POOL_MAX, # autocommit=False면 SELECT만 하고 반납된 커넥션에 열린 트랜잭션(옛 스냅샷)이 # 남아, 다른 커넥션이 커밋한 데이터(예: 방금 생성된 세션)를 못 읽는다. # 다중 문장 트랜잭션은 connection.begin()을 명시적으로 사용한다. autocommit=True, charset="utf8mb4", init_command="SET time_zone='+00:00'", ) return db_pool async def close_db_pool() -> None: """MariaDB 연결 풀 종료""" global db_pool if db_pool: db_pool.close() await db_pool.wait_closed() db_pool = None def get_db_pool() -> aiomysql.Pool: """현재 활성 DB 풀 반환. 없으면 RuntimeError""" if not db_pool: raise RuntimeError("DB pool not initialized. Call init_db_pool() first.") return db_pool async def run_with_connection(repository_call: Callable[..., Any], *args: Any) -> Any: """저장소 함수 하나를 **자기 커넥션**으로 실행한다 — `asyncio.gather` 로 묶기 위한 것. DB 가 원격이라 질의 하나가 곧 왕복 약 12ms 다(2026-09-06 실측). 서로 기다릴 이유가 없는 읽기를 한 커넥션에서 순차로 내면 그 왕복이 그대로 더해진다. 커넥션을 갈라 같이 보내면 가장 느린 하나의 시간만 든다. 풀 최대치는 `DB_POOL_MAX`(기본 20). ⚠ **읽기에만 쓸 것.** 순서가 필요한 쓰기(한 트랜잭션 안의 UPDATE 들)를 이걸로 묶으면 커넥션이 갈려 트랜잭션이 깨진다. """ pool = get_db_pool() async with pool.acquire() as connection: return await repository_call(connection, *args)