| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960 |
- """SQLAlchemy 数据库连接与会话工具。
- Engine 管理数据库连接池;Session 表示一次数据库工作单元,负责查询和提交事务。
- """
- from collections.abc import Iterator
- from enum import StrEnum
- from sqlalchemy import URL, Engine, create_engine
- from sqlalchemy.orm import Session, sessionmaker
- from app.core.config import Settings
- class DatabaseName(StrEnum):
- """三个业务数据库的逻辑名称,使用枚举可避免到处手写字符串。"""
- CORE = "core"
- AGENT = "agent"
- ANALYTICS = "analytics"
- def build_mysql_url(settings: Settings, database: DatabaseName) -> URL:
- """根据配置和目标数据库生成 SQLAlchemy 连接地址。"""
- database_names = {
- DatabaseName.CORE: settings.mysql_core_database,
- DatabaseName.AGENT: settings.mysql_agent_database,
- DatabaseName.ANALYTICS: settings.mysql_analytics_database,
- }
- return URL.create(
- drivername="mysql+pymysql",
- username=settings.mysql_user,
- password=settings.mysql_password,
- host=settings.mysql_host,
- port=settings.mysql_port,
- database=database_names[database],
- query={"charset": "utf8mb4"},
- )
- def create_mysql_engine(settings: Settings, database: DatabaseName) -> Engine:
- """创建连接池;此时通常还不会立刻执行 SQL。"""
- return create_engine(
- build_mysql_url(settings, database),
- # 借出连接前先检查连接是否有效,避免拿到已被 MySQL 关闭的旧连接。
- pool_pre_ping=True,
- # 定期回收连接,降低 MySQL 服务端超时导致断连的概率。
- pool_recycle=1800,
- )
- def create_session_factory(engine: Engine) -> sessionmaker[Session]:
- """创建 Session 工厂;调用这个工厂才能得到具体会话。"""
- return sessionmaker(bind=engine, expire_on_commit=False)
- def session_scope(factory: sessionmaker[Session]) -> Iterator[Session]:
- """提供自动提交/回滚的会话上下文,yield 把会话交给调用方使用。"""
- with factory.begin() as session:
- yield session
|