refactor(database): 阶段一 - 创建新架构基础
- 创建分层目录结构 (core/api/optimization/config/utils) - 实现核心层: engine.py, session.py - 实现配置层: database_config.py - 实现工具层: exceptions.py - 迁移连接池管理器到优化层 - 添加详细的重构计划文档
This commit is contained in:
21
src/common/database/core/__init__.py
Normal file
21
src/common/database/core/__init__.py
Normal file
@@ -0,0 +1,21 @@
|
||||
"""数据库核心层
|
||||
|
||||
职责:
|
||||
- 数据库引擎管理
|
||||
- 会话管理
|
||||
- 模型定义
|
||||
- 数据库迁移
|
||||
"""
|
||||
|
||||
from .engine import close_engine, get_engine, get_engine_info
|
||||
from .session import get_db_session, get_db_session_direct, get_session_factory, reset_session_factory
|
||||
|
||||
__all__ = [
|
||||
"get_engine",
|
||||
"close_engine",
|
||||
"get_engine_info",
|
||||
"get_db_session",
|
||||
"get_db_session_direct",
|
||||
"get_session_factory",
|
||||
"reset_session_factory",
|
||||
]
|
||||
141
src/common/database/core/engine.py
Normal file
141
src/common/database/core/engine.py
Normal file
@@ -0,0 +1,141 @@
|
||||
"""数据库引擎管理
|
||||
|
||||
单一职责:创建和管理SQLAlchemy异步引擎
|
||||
"""
|
||||
|
||||
import asyncio
|
||||
from typing import Optional
|
||||
|
||||
from sqlalchemy import text
|
||||
from sqlalchemy.ext.asyncio import AsyncEngine, create_async_engine
|
||||
|
||||
from src.common.logger import get_logger
|
||||
|
||||
from ..config.database_config import get_database_config
|
||||
from ..utils.exceptions import DatabaseInitializationError
|
||||
|
||||
logger = get_logger("database.engine")
|
||||
|
||||
# 全局引擎实例
|
||||
_engine: Optional[AsyncEngine] = None
|
||||
_engine_lock: Optional[asyncio.Lock] = None
|
||||
|
||||
|
||||
async def get_engine() -> AsyncEngine:
|
||||
"""获取全局数据库引擎(单例模式)
|
||||
|
||||
Returns:
|
||||
AsyncEngine: SQLAlchemy异步引擎
|
||||
|
||||
Raises:
|
||||
DatabaseInitializationError: 引擎初始化失败
|
||||
"""
|
||||
global _engine, _engine_lock
|
||||
|
||||
# 快速路径:引擎已初始化
|
||||
if _engine is not None:
|
||||
return _engine
|
||||
|
||||
# 延迟创建锁(避免在导入时创建)
|
||||
if _engine_lock is None:
|
||||
_engine_lock = asyncio.Lock()
|
||||
|
||||
# 使用锁保护初始化过程
|
||||
async with _engine_lock:
|
||||
# 双重检查锁定模式
|
||||
if _engine is not None:
|
||||
return _engine
|
||||
|
||||
try:
|
||||
config = get_database_config()
|
||||
|
||||
logger.info(f"正在初始化 {config.db_type.upper()} 数据库引擎...")
|
||||
|
||||
# 创建异步引擎
|
||||
_engine = create_async_engine(
|
||||
config.url,
|
||||
**config.engine_kwargs
|
||||
)
|
||||
|
||||
# SQLite特定优化
|
||||
if config.db_type == "sqlite":
|
||||
await _enable_sqlite_optimizations(_engine)
|
||||
|
||||
logger.info(f"✅ {config.db_type.upper()} 数据库引擎初始化成功")
|
||||
return _engine
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"❌ 数据库引擎初始化失败: {e}", exc_info=True)
|
||||
raise DatabaseInitializationError(f"引擎初始化失败: {e}") from e
|
||||
|
||||
|
||||
async def close_engine():
|
||||
"""关闭数据库引擎
|
||||
|
||||
释放所有连接池资源
|
||||
"""
|
||||
global _engine
|
||||
|
||||
if _engine is not None:
|
||||
logger.info("正在关闭数据库引擎...")
|
||||
await _engine.dispose()
|
||||
_engine = None
|
||||
logger.info("✅ 数据库引擎已关闭")
|
||||
|
||||
|
||||
async def _enable_sqlite_optimizations(engine: AsyncEngine):
|
||||
"""启用SQLite性能优化
|
||||
|
||||
优化项:
|
||||
- WAL模式:提高并发性能
|
||||
- NORMAL同步:平衡性能和安全性
|
||||
- 启用外键约束
|
||||
- 设置busy_timeout:避免锁定错误
|
||||
|
||||
Args:
|
||||
engine: SQLAlchemy异步引擎
|
||||
"""
|
||||
try:
|
||||
async with engine.begin() as conn:
|
||||
# 启用WAL模式
|
||||
await conn.execute(text("PRAGMA journal_mode = WAL"))
|
||||
# 设置适中的同步级别
|
||||
await conn.execute(text("PRAGMA synchronous = NORMAL"))
|
||||
# 启用外键约束
|
||||
await conn.execute(text("PRAGMA foreign_keys = ON"))
|
||||
# 设置busy_timeout,避免锁定错误
|
||||
await conn.execute(text("PRAGMA busy_timeout = 60000"))
|
||||
# 设置缓存大小(10MB)
|
||||
await conn.execute(text("PRAGMA cache_size = -10000"))
|
||||
# 临时存储使用内存
|
||||
await conn.execute(text("PRAGMA temp_store = MEMORY"))
|
||||
|
||||
logger.info("✅ SQLite性能优化已启用 (WAL模式 + 并发优化)")
|
||||
|
||||
except Exception as e:
|
||||
logger.warning(f"⚠️ SQLite性能优化失败: {e},将使用默认配置")
|
||||
|
||||
|
||||
async def get_engine_info() -> dict:
|
||||
"""获取引擎信息(用于监控和调试)
|
||||
|
||||
Returns:
|
||||
dict: 引擎信息字典
|
||||
"""
|
||||
try:
|
||||
engine = await get_engine()
|
||||
|
||||
info = {
|
||||
"name": engine.name,
|
||||
"driver": engine.driver,
|
||||
"url": str(engine.url).replace(str(engine.url.password or ""), "***"),
|
||||
"pool_size": getattr(engine.pool, "size", lambda: None)(),
|
||||
"pool_checked_out": getattr(engine.pool, "checked_out", lambda: 0)(),
|
||||
"pool_overflow": getattr(engine.pool, "overflow", lambda: 0)(),
|
||||
}
|
||||
|
||||
return info
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"获取引擎信息失败: {e}")
|
||||
return {}
|
||||
118
src/common/database/core/session.py
Normal file
118
src/common/database/core/session.py
Normal file
@@ -0,0 +1,118 @@
|
||||
"""数据库会话管理
|
||||
|
||||
单一职责:提供数据库会话工厂和上下文管理器
|
||||
"""
|
||||
|
||||
import asyncio
|
||||
from collections.abc import AsyncGenerator
|
||||
from contextlib import asynccontextmanager
|
||||
from typing import Optional
|
||||
|
||||
from sqlalchemy import text
|
||||
from sqlalchemy.ext.asyncio import AsyncSession, async_sessionmaker
|
||||
|
||||
from src.common.logger import get_logger
|
||||
|
||||
from ..config.database_config import get_database_config
|
||||
from .engine import get_engine
|
||||
|
||||
logger = get_logger("database.session")
|
||||
|
||||
# 全局会话工厂
|
||||
_session_factory: Optional[async_sessionmaker] = None
|
||||
_factory_lock: Optional[asyncio.Lock] = None
|
||||
|
||||
|
||||
async def get_session_factory() -> async_sessionmaker:
|
||||
"""获取会话工厂(单例模式)
|
||||
|
||||
Returns:
|
||||
async_sessionmaker: SQLAlchemy异步会话工厂
|
||||
"""
|
||||
global _session_factory, _factory_lock
|
||||
|
||||
# 快速路径
|
||||
if _session_factory is not None:
|
||||
return _session_factory
|
||||
|
||||
# 延迟创建锁
|
||||
if _factory_lock is None:
|
||||
_factory_lock = asyncio.Lock()
|
||||
|
||||
async with _factory_lock:
|
||||
# 双重检查
|
||||
if _session_factory is not None:
|
||||
return _session_factory
|
||||
|
||||
engine = await get_engine()
|
||||
_session_factory = async_sessionmaker(
|
||||
bind=engine,
|
||||
class_=AsyncSession,
|
||||
expire_on_commit=False, # 避免在commit后访问属性时重新查询
|
||||
)
|
||||
|
||||
logger.debug("会话工厂已创建")
|
||||
return _session_factory
|
||||
|
||||
|
||||
@asynccontextmanager
|
||||
async def get_db_session() -> AsyncGenerator[AsyncSession, None]:
|
||||
"""获取数据库会话上下文管理器
|
||||
|
||||
这是数据库操作的主要入口点,通过连接池管理器提供透明的连接复用。
|
||||
|
||||
使用示例:
|
||||
async with get_db_session() as session:
|
||||
result = await session.execute(select(User))
|
||||
users = result.scalars().all()
|
||||
|
||||
Yields:
|
||||
AsyncSession: SQLAlchemy异步会话对象
|
||||
"""
|
||||
# 延迟导入避免循环依赖
|
||||
from ..optimization.connection_pool import get_connection_pool_manager
|
||||
|
||||
session_factory = await get_session_factory()
|
||||
pool_manager = get_connection_pool_manager()
|
||||
|
||||
# 使用连接池管理器(透明复用连接)
|
||||
async with pool_manager.get_session(session_factory) as session:
|
||||
# 为SQLite设置特定的PRAGMA
|
||||
config = get_database_config()
|
||||
if config.db_type == "sqlite":
|
||||
try:
|
||||
await session.execute(text("PRAGMA busy_timeout = 60000"))
|
||||
await session.execute(text("PRAGMA foreign_keys = ON"))
|
||||
except Exception:
|
||||
# 复用连接时PRAGMA可能已设置,忽略错误
|
||||
pass
|
||||
|
||||
yield session
|
||||
|
||||
|
||||
@asynccontextmanager
|
||||
async def get_db_session_direct() -> AsyncGenerator[AsyncSession, None]:
|
||||
"""获取数据库会话(直接模式,不使用连接池)
|
||||
|
||||
用于特殊场景,如需要完全独立的连接时。
|
||||
一般情况下应使用 get_db_session()。
|
||||
|
||||
Yields:
|
||||
AsyncSession: SQLAlchemy异步会话对象
|
||||
"""
|
||||
session_factory = await get_session_factory()
|
||||
|
||||
async with session_factory() as session:
|
||||
try:
|
||||
yield session
|
||||
except Exception:
|
||||
await session.rollback()
|
||||
raise
|
||||
finally:
|
||||
await session.close()
|
||||
|
||||
|
||||
async def reset_session_factory():
|
||||
"""重置会话工厂(用于测试)"""
|
||||
global _session_factory
|
||||
_session_factory = None
|
||||
Reference in New Issue
Block a user