database.py 2.3 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374
  1. """
  2. 数据库配置模块
  3. 提供数据库连接、会话管理和依赖注入功能
  4. """
  5. import os
  6. from pathlib import Path
  7. from sqlalchemy import create_engine
  8. from sqlalchemy.ext.declarative import declarative_base
  9. from sqlalchemy.orm import sessionmaker
  10. from dotenv import load_dotenv
  11. # 加载环境变量(从backend目录的.env文件)
  12. env_path = Path(__file__).parent.parent / '.env'
  13. load_dotenv(dotenv_path=env_path)
  14. # 从环境变量读取数据库配置
  15. DB_HOST = os.getenv("DB_HOST", "localhost")
  16. DB_PORT = os.getenv("DB_PORT", "5432")
  17. DB_USER = os.getenv("DB_USER", "postgres")
  18. DB_PASSWORD = os.getenv("DB_PASSWORD", "")
  19. DB_NAME = os.getenv("DB_NAME", "model_square")
  20. # 连接池配置说明:
  21. # gunicorn 多进程模式下,每个 worker 都有独立连接池
  22. # 总连接数 = workers × (pool_size + max_overflow)
  23. # 服务器 2核 → workers ≈ 5,pool_size=5 → 总连接 ≈ 25,不超过 PostgreSQL 默认 100
  24. # 如果升级到 4核 → workers ≈ 9,pool_size=5 → 总连接 ≈ 45,仍然安全
  25. DB_POOL_SIZE = int(os.getenv("DB_POOL_SIZE", "5"))
  26. DB_MAX_OVERFLOW = int(os.getenv("DB_MAX_OVERFLOW", "10"))
  27. DB_POOL_TIMEOUT = int(os.getenv("DB_POOL_TIMEOUT", "10")) # 等待连接超时缩短到 10s,快速失败
  28. DB_POOL_RECYCLE = int(os.getenv("DB_POOL_RECYCLE", "1800"))
  29. # 构建数据库连接URL(对密码进行URL编码,处理特殊字符如@)
  30. from urllib.parse import quote_plus
  31. DATABASE_URL = f"postgresql://{DB_USER}:{quote_plus(DB_PASSWORD)}@{DB_HOST}:{DB_PORT}/{DB_NAME}"
  32. # 创建数据库引擎
  33. engine = create_engine(
  34. DATABASE_URL,
  35. pool_size=DB_POOL_SIZE,
  36. max_overflow=DB_MAX_OVERFLOW,
  37. pool_timeout=DB_POOL_TIMEOUT,
  38. pool_recycle=DB_POOL_RECYCLE, # 定期回收连接,防止远程数据库断开空闲连接
  39. pool_pre_ping=True,
  40. echo=False
  41. )
  42. # 创建会话工厂
  43. SessionLocal = sessionmaker(
  44. autocommit=False,
  45. autoflush=False,
  46. bind=engine
  47. )
  48. # 创建基类
  49. Base = declarative_base()
  50. def get_db():
  51. """
  52. 数据库会话依赖注入函数
  53. 用于FastAPI的依赖注入系统,自动管理数据库会话的生命周期
  54. 确保请求结束后会话被正确关闭
  55. Yields:
  56. Session: 数据库会话对象
  57. """
  58. db = SessionLocal()
  59. try:
  60. yield db
  61. finally:
  62. db.close()