SQLAlchemy中的会话与连接关系
会话(Session)与连接(Connection)的区别
在SQLAlchemy中,Session和Connection是两个不同的概念:
-
Session(会话):
- 是SQLAlchemy ORM的核心概念
- 作为对象和数据库之间的中介
- 管理对象的状态跟踪、事务和查询
- 不直接等同于数据库连接
- 一个Session可以在其生命周期内使用多个连接
-
Connection(连接):
- 是与数据库的实际连接
- 由Session在需要时从连接池获取
- 执行完查询后返回给连接池(除非显式保持)
- 代表真正的数据库网络连接
Session使用Connection的方式
Session使用Connection的关键特性:
-
延迟获取连接:
- Session不会在创建时就获取连接
- 只有在实际执行数据库操作时才获取连接
-
按需使用连接:
- 执行查询时获取连接
- 查询完成后默认释放连接回池
- 在事务内会保持连接直到事务结束
-
连接复用:
- 在同一事务中的多个查询会复用同一个连接
- 不同事务可能使用不同的连接
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测试连接
)
连接池的工作流程
-
连接获取:
应用请求连接 → Engine检查池 → 若有空闲连接返回 → 若无空闲连接且未达上限则创建新连接 → 若达上限则等待或错误 -
连接返回:
操作完成 → 连接返回池 → 连接保持打开状态 → 供后续请求使用 -
连接回收:
连接超过pool_recycle时间 → 下次使用前关闭并创建新连接
连接池在代码中的体现
-
引擎创建:
# 通常在应用启动时创建 engine = create_engine('connection_string', pool_size=20, ...) -
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] -
在执行查询时:
# 当执行如下代码时 result = session.query(Model).all() # 内部会从连接池获取连接,查询完成后释放回池
多Session
创建多个Session是否会导致创建多个连接?
不一定。关键点如下:
-
Session ≠ Connection:
- 创建多个Session不等于创建多个持久连接
- 连接的数量由实际同时执行的查询数决定
-
连接池复用:
- 多个Session可以共享连接池中的连接
- 当Session A释放连接后,Session B可以复用它
-
实际影响:
- 如果同一时间有大量活跃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}")
总结
-
Session与连接的关系:
- Session不等同于数据库连接
- 连接由Session按需从连接池获取和释放
- 未提交的事务会持有连接直到事务结束
-
连接池的作用:
- 减少连接创建和关闭的开销
- 限制并管理最大连接数
- 提供连接回收和健康检查机制