SQLAlchemy:创build与重用会话

只是一个简单的问题:SQLAlchemy会谈论调用sessionmaker()一次,但每次需要与您的数据库交谈时调用生成的Session()类。 对于我来说这意味着第二次我会做我的第一次session.add(x)或类似的东西,我会先做

 from project import Session session = Session() 

到目前为止我所做的是在我的模型中调用session = Session() ,然后在应用程序中的任何位置总是导入相同的会话。 由于这是一个web应用程序,这通常意味着相同的(作为一个视图执行)。

但是区别在哪里? 使用一个会话一直反对使用它的数据库的东西,直到我的function完成,然后创build一个新的下一次我想谈谈我的数据库的缺点是什么?

我得到,如果我使用多个线程,每个人应该得到自己的会议。 但是使用scoped_session() ,我已经确定这个问题不存在,是吗?

请澄清我的假设是否有错误。

sessionmaker()是一个工厂,它鼓励在一个地方放置用于创build新的Session对象的configuration选项。 这是可选的,因为在需要一个新的Session时候,你可以简单地调用Session(bind=engine, expire_on_commit=False) ,除了它冗长而冗余,并且我想阻止小规模的“助手”每个人都以一种新的和更混乱的方式来处理这个冗余问题。

所以sessionmaker()只是一个帮助你在需要的时候创buildSession对象的工具。

下一部分。 我认为问题在于,在不同的时间点build立一个新的Session()与仅仅使用一个Session()什么不同。 答案不是很多。 Session是你放入它的所有对象的容器,然后它也跟踪一个打开的事务。 在调用rollback()commit()的那一刻,事务结束,并且Session被调用以再次发出SQL之前,没有连接到数据库。 如果对象没有挂起的变化,它保存到映射对象的链接是弱引用,所以即使在这种情况下,当应用程序丢失对映射对象的所有引用时, Session也会自行退出到全新的状态。 如果您保留默认的"expire_on_commit"设置,则所有对象在提交后都会过期。 如果该Session挂起五到二十分钟,并且下一次使用它时数据库中的所有事情都发生了变化,那么即使它们已经坐在这里,它也会在下次访问这些对象时加载所有全新的状态记忆二十分钟。

在Web应用程序中,我们通常会说,嘿,为什么不在每个请求上创build一个全新的Session ,而不是一次又一次地使用同一个Session 。 这种做法确保新的请求开始“清洁”。 如果前一个请求中的某些对象还没有被垃圾收集,并且如果您closures了"expire_on_commit" ,那么前一个请求中的某个状态可能还是处于"expire_on_commit"状态,而且这个状态甚至可能会很老。 如果你仔细地开启了expire_on_commit ,并且在请求结束时肯定地调用了commit()或者rollback() ,那么没关系,但是如果你从一个全新的Session ,那么你甚至不会有任何问题清洁。 因此,使用新Session启动每个请求的想法实际上只是最简单的方法,以确保您开始新鲜,并使expire_on_commit的使用非常可选,因为此标志可能会招致大量额外的SQL操作在一系列操作的中间调用commit() 。 不知道这是否回答你的问题。

下一轮是你提到的线程。 如果您的应用程序是multithreading的,我们build议确保使用的Session是本地… …的东西。 scoped_session()默认使其成为当前线程的本地。 在一个networking应用程序中,请求的本地事实上甚至更好。 Flask-SQLAlchemy实际上向scoped_session()发送了一个自定义的“范围函数”,以便获得一个请求范围的会话。 平均金字塔应用程序将会话粘贴到“请求”registry中。 当使用这样的scheme时,“根据请求创build新的会话开始”的想法继续看起来像保持直线的最直接的方式。

除了优秀的zzzeek的回答,这里有一个简单的方法来快速创build一次性的,自我封闭的会议:

 from contextlib import contextmanager from sqlalchemy import create_engine from sqlalchemy.orm import scoped_session, sessionmaker @contextmanager def db_session(db_url): """ Creates a context with an open SQLAlchemy session. """ engine = create_engine(db_url, convert_unicode=True) connection = engine.connect() db_session = scoped_session(sessionmaker(autocommit=False, autoflush=True, bind=engine)) yield db_session db_session.close() connection.close() 

用法:

 from mymodels import Foo with db_session("sqlite://") as db: foos = db.query(Foo).all() 

您可以使用数据库创build会话

 db = SQLAlchemy(app) engine = db.engine Session = sessionmaker(engine) session = Session()