SQLAlchemy使用scoped_session上下文管理器时add方法无法插入数据如何解决
问题根本原因
- 你为session设置了
autoflush=False,db.add()仅会将实例对象加入会话的pending队列,不会自动触发flush生成INSERT语句发送到数据库。而query、update、delete这类需要和数据库交互的操作,会默认触发flush同步pending变更,所以这些操作可以正常执行。 - 你设置的
autocommit=True并不会自动提交add产生的待提交变更,该参数在SQLAlchemy 1.4及以上版本已被废弃,它的实际作用是禁用会话的隐式事务,不会主动帮你提交未flush的变更。你没有手动调用commit的前提下,会话关闭时pending的插入操作会直接丢弃,不会持久化到数据库。 - 你自定义的上下文管理器设计不合理:
scoped_session的设计目标是实现线程/上下文维度的会话复用,你每次进入上下文都重新创建引擎、会话工厂、scoped_session,完全浪费了该特性的能力,还会带来不必要的连接池开销;此外你手动创建的connection完全没有被会话使用,属于冗余代码,还可能导致连接泄漏问题。
修复方案
首先调整会话初始化逻辑,将引擎、会话工厂的初始化从上下文管理器中剥离,在上下文退出时自动处理提交/回滚逻辑:
from sqlalchemy import create_engine from sqlalchemy.orm import scoped_session, sessionmaker, declarative_base # 全局初始化一次引擎和会话工厂即可 engine = create_engine("sqlite:///test.db", echo = True) db_session = scoped_session(sessionmaker( autoflush=False, bind=engine )) Base = declarative_base() Base.query = db_session.query_property() # 上下文管理器实现 class SessionContext: def __enter__(self): return db_session def __exit__(self, exc_type, exc_val, exc_tb): if exc_type is None: # 无异常则提交变更 db_session.commit() else: # 有异常则回滚 db_session.rollback() db_session.remove()
调整后插入逻辑不需要额外修改,直接使用新的上下文管理器即可:
def insert_value(a, b, c): with SessionContext() as db: db.add(Value(a = a, b = b, c = c))
如果不想调整上下文管理器,也可以在调用db.add()之后手动执行db.flush()+db.commit()完成插入,但更推荐上下文自动处理提交/回滚的方案,避免漏写提交导致的数据丢失问题。
内容的提问来源于stack exchange,提问作者raspbagel
相关产品推荐
相关产品推荐

