2026-03-23 11:08:52 +08:00
|
|
|
|
import os
|
2026-03-24 23:16:35 +08:00
|
|
|
|
import time
|
|
|
|
|
|
from sqlalchemy import create_engine, event
|
2026-03-23 11:08:52 +08:00
|
|
|
|
from sqlalchemy.ext.declarative import declarative_base
|
|
|
|
|
|
from sqlalchemy.orm import sessionmaker
|
2026-03-24 23:16:35 +08:00
|
|
|
|
from sqlalchemy.pool import QueuePool
|
|
|
|
|
|
from typing import Generator
|
|
|
|
|
|
import logging
|
|
|
|
|
|
|
|
|
|
|
|
logger = logging.getLogger(__name__)
|
2026-03-23 11:08:52 +08:00
|
|
|
|
|
|
|
|
|
|
DATABASE_URL = os.getenv(
|
|
|
|
|
|
"DATABASE_URL",
|
2026-04-06 15:06:11 +08:00
|
|
|
|
"postgresql://postgres:postgres@127.0.0.1:5432/zodiac"
|
2026-03-23 11:08:52 +08:00
|
|
|
|
)
|
|
|
|
|
|
|
2026-03-24 23:16:35 +08:00
|
|
|
|
# 增强版数据库引擎配置
|
2026-03-23 11:08:52 +08:00
|
|
|
|
engine = create_engine(
|
|
|
|
|
|
DATABASE_URL,
|
2026-03-24 23:16:35 +08:00
|
|
|
|
# 连接池配置
|
|
|
|
|
|
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秒
|
|
|
|
|
|
}
|
2026-03-23 11:08:52 +08:00
|
|
|
|
)
|
|
|
|
|
|
|
2026-03-24 23:16:35 +08:00
|
|
|
|
# 添加连接事件监听器
|
|
|
|
|
|
@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("数据库连接无效")
|
|
|
|
|
|
|
2026-03-23 11:08:52 +08:00
|
|
|
|
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
|
|
|
|
|
|
|
|
|
|
|
|
Base = declarative_base()
|
|
|
|
|
|
|
2026-03-24 23:16:35 +08:00
|
|
|
|
def get_db() -> Generator:
|
|
|
|
|
|
"""获取数据库会话,带错误处理"""
|
2026-03-23 11:08:52 +08:00
|
|
|
|
db = SessionLocal(expire_on_commit=False)
|
|
|
|
|
|
try:
|
|
|
|
|
|
yield db
|
2026-03-24 23:16:35 +08:00
|
|
|
|
except Exception as e:
|
|
|
|
|
|
logger.error(f"数据库会话错误: {e}")
|
|
|
|
|
|
db.rollback()
|
|
|
|
|
|
raise
|
2026-03-23 11:08:52 +08:00
|
|
|
|
finally:
|
|
|
|
|
|
db.close()
|