import os import time from sqlalchemy import create_engine, event from sqlalchemy.ext.declarative import declarative_base from sqlalchemy.orm import sessionmaker from sqlalchemy.pool import QueuePool from typing import Generator import logging logger = logging.getLogger(__name__) DATABASE_URL = os.getenv( "DATABASE_URL", "postgresql://postgres:postgres@127.0.0.1:5432/zodiac" ) # 增强版数据库引擎配置 engine = create_engine( DATABASE_URL, # 连接池配置 poolclass=QueuePool, pool_size=20, # 常规连接数 max_overflow=40, # 允许超出的连接数(高并发时) pool_timeout=30, # 获取连接超时时间(秒) pool_recycle=1800, # 连接回收时间(30分钟),避免连接过期 pool_pre_ping=True, # 每次获取连接前检查连接是否有效 echo=False, # 连接参数优化 connect_args={ "connect_timeout": 10, "application_name": "zodiac-api", "options": "-c statement_timeout=30000" # 查询超时30秒 } ) # 添加连接事件监听器 @event.listens_for(engine, "connect") def set_connect_timeout(dbapi_conn, connection_record): """设置连接参数""" cursor = dbapi_conn.cursor() cursor.execute("SET statement_timeout = 30000") cursor.close() @event.listens_for(engine, "checkout") def check_connection(dbapi_conn, connection_record, connection_proxy): """检出连接时检查""" try: cursor = dbapi_conn.cursor() cursor.execute("SELECT 1") cursor.close() except Exception as e: logger.warning(f"连接检查失败: {e}") raise Exception("数据库连接无效") SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine) Base = declarative_base() def get_db() -> Generator: """获取数据库会话,带错误处理""" db = SessionLocal(expire_on_commit=False) try: yield db except Exception as e: logger.error(f"数据库会话错误: {e}") db.rollback() raise finally: db.close()