| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108 |
- """MySQL 异步后端 —— 基于 aiomysql 连接池"""
- import logging
- from typing import Any, Optional
- from aiomysql import create_pool, DictCursor
- from supply.infra.database.ports import SqlBackend
- logger = logging.getLogger(__name__)
- class MySQLBackend(SqlBackend):
- """MySQL 异步连接池后端"""
- def __init__(self, name: str, config: Any):
- super().__init__(name, config)
- self._pool = None
- # ==================== 生命周期 ====================
- async def init(self) -> None:
- if self._initialized:
- return
- self._pool = await create_pool(
- host=self.config.host,
- port=self.config.port,
- user=self.config.user,
- password=self.config.password,
- db=self.config.db,
- charset=getattr(self.config, "charset", "utf8mb4"),
- minsize=getattr(self.config, "minsize", 5),
- maxsize=getattr(self.config, "maxsize", 20),
- cursorclass=DictCursor,
- autocommit=True,
- )
- self._initialized = True
- logger.info("MySQL backend [%s] 连接池创建成功", self.name)
- async def close(self) -> None:
- if self._pool is None:
- return
- self._pool.close()
- await self._pool.wait_closed()
- self._pool = None
- self._initialized = False
- logger.info("MySQL backend [%s] 连接池已关闭", self.name)
- async def health(self) -> bool:
- try:
- await self.fetch_one("SELECT 1")
- return True
- except Exception:
- return False
- # ==================== SQL 操作 ====================
- async def fetch(
- self,
- query: str,
- params: Optional[tuple] = None,
- ) -> list[dict]:
- self._ensure_ready()
- async with self._pool.acquire() as conn:
- async with conn.cursor(DictCursor) as cursor:
- await cursor.execute(query, params)
- return await cursor.fetchall()
- async def fetch_one(
- self,
- query: str,
- params: Optional[tuple] = None,
- ) -> Optional[dict]:
- self._ensure_ready()
- async with self._pool.acquire() as conn:
- async with conn.cursor(DictCursor) as cursor:
- await cursor.execute(query, params)
- return await cursor.fetchone()
- async def execute(
- self,
- query: str,
- params: Any = None,
- *,
- batch: bool = False,
- ) -> int:
- self._ensure_ready()
- async with self._pool.acquire() as conn:
- async with conn.cursor() as cursor:
- try:
- if batch:
- await cursor.executemany(query, params)
- else:
- await cursor.execute(query, params)
- affected = cursor.rowcount
- await conn.commit()
- return affected
- except Exception:
- await conn.rollback()
- raise
- # ==================== 内部 ====================
- def _ensure_ready(self):
- if not self._initialized or self._pool is None:
- raise RuntimeError(
- f"MySQL backend [{self.name}] 未初始化,请先调用 init()"
- )
|