SQLAlchemy会话与连接池分析

274 阅读3分钟

SQLAlchemy中的会话与连接关系

会话(Session)与连接(Connection)的区别

在SQLAlchemy中,Session和Connection是两个不同的概念:

  1. Session(会话)

    • 是SQLAlchemy ORM的核心概念
    • 作为对象和数据库之间的中介
    • 管理对象的状态跟踪、事务和查询
    • 不直接等同于数据库连接
    • 一个Session可以在其生命周期内使用多个连接
  2. Connection(连接)

    • 是与数据库的实际连接
    • 由Session在需要时从连接池获取
    • 执行完查询后返回给连接池(除非显式保持)
    • 代表真正的数据库网络连接

Session使用Connection的方式

Session使用Connection的关键特性:

  1. 延迟获取连接

    • Session不会在创建时就获取连接
    • 只有在实际执行数据库操作时才获取连接
  2. 按需使用连接

    • 执行查询时获取连接
    • 查询完成后默认释放连接回池
    • 在事务内会保持连接直到事务结束
  3. 连接复用

    • 在同一事务中的多个查询会复用同一个连接
    • 不同事务可能使用不同的连接

SQLAlchemy的连接池机制

连接池的实现

SQLAlchemy的连接池是通过Engine对象来管理的:

from sqlalchemy import create_engine

engine = create_engine(
    'mysql+pymysql://user:pass@localhost/db',
    pool_size=20,           # 池中保持的连接数
    max_overflow=10,        # 允许超出pool_size的连接数
    pool_timeout=30,        # 等待连接的超时时间
    pool_recycle=3600,      # 连接最大生存时间(秒)
    pool_pre_ping=True      # 使用前ping测试连接
)

连接池的工作流程

  1. 连接获取

    应用请求连接 → Engine检查池 → 若有空闲连接返回 → 若无空闲连接且未达上限则创建新连接 → 若达上限则等待或错误
    
  2. 连接返回

    操作完成 → 连接返回池 → 连接保持打开状态 → 供后续请求使用
    
  3. 连接回收

    连接超过pool_recycle时间 → 下次使用前关闭并创建新连接
    

连接池在代码中的体现

  1. 引擎创建

    # 通常在应用启动时创建
    engine = create_engine('connection_string', pool_size=20, ...)
    
  2. Session工厂使用引擎时

    # 在session_manager.py中
    def get_session(self, engine_name):
        if engine_name not in self.sessions:
            engine = self.engines[engine_name]
            Session = sessionmaker(bind=engine)  # 这里引用了带连接池的引擎
            self.sessions[engine_name] = Session()
        return self.sessions[engine_name]
    
  3. 在执行查询时

    # 当执行如下代码时
    result = session.query(Model).all()
    # 内部会从连接池获取连接,查询完成后释放回池
    

多Session

创建多个Session是否会导致创建多个连接?

不一定。关键点如下:

  1. Session ≠ Connection

    • 创建多个Session不等于创建多个持久连接
    • 连接的数量由实际同时执行的查询数决定
  2. 连接池复用

    • 多个Session可以共享连接池中的连接
    • 当Session A释放连接后,Session B可以复用它
  3. 实际影响

    • 如果同一时间有大量活跃Session同时执行查询,才会导致连接数增加
    • 连接池参数(pool_size和max_overflow)控制最大连接数
    • 会话未提交的事务会占用连接直到会话关闭或事务提交/回滚

监控和诊断连接池

为了确保连接池工作正常,添加监控代码:

def check_engine_pool_status(engine):
    """检查引擎连接池状态"""
    status = {
        'pool_size': engine.pool.size(),
        'checkedin': engine.pool.checkedin(),
        'checkedout': engine.pool.checkedout(),
        'overflow': engine.pool.overflow(),
        'total_connections': engine.pool.checkedin() + engine.pool.checkedout(),
        'max_connections': engine.pool.size() + engine.pool.max_overflow
    }
    return status

# 注册定期任务检查连接池状态
@app.task
def monitor_db_connections():
    for engine_name, engine in engines.items():
        status = check_engine_pool_status(engine)
        logger.info(f"Engine {engine_name} connection pool: {status}")

总结

  1. Session与连接的关系

    • Session不等同于数据库连接
    • 连接由Session按需从连接池获取和释放
    • 未提交的事务会持有连接直到事务结束
  2. 连接池的作用

    • 减少连接创建和关闭的开销
    • 限制并管理最大连接数
    • 提供连接回收和健康检查机制