在SQLAlchemy中使用scoped_session(sessionmaker())还是普通的sessionmaker()?
我在我的网页项目中使用SQLAlchemy。我应该用scoped_session(sessionmaker())
还是普通的sessionmaker()
,为什么?或者我应该用别的什么吗?
## model.py
from sqlalchemy import *
from sqlalchemy.orm import *
engine = create_engine('mysql://dbUser:dbPassword@dbServer:dbPort/dbName',
pool_recycle=3600, echo=False)
metadata = MetaData(engine)
Session = scoped_session(sessionmaker())
Session.configure(bind=engine)
user = Table('user', metadata, autoload=True)
class User(object):
pass
usermapper = mapper(User, user)
## some other python file called abc.py
from models import *
def getalluser():
session = Session()
session.query(User).all()
session.flush()
session.close()
## onemore file defg.py
from models import *
def updateuser():
session = Session()
session.query(User).filter(User.user_id == '4').update({User.user_lname: 'villkoo'})
session.commit()
session.flush()
session.close()
我为每个请求创建一个session = Session()
对象,然后关闭它。这样做对吗?还是有更好的方法?
5 个回答
不要使用scoped_session,也不要使用Flask-SQLAlchemy。
直接使用 Session = sessionmaker()
,把它放在一个单例或服务类里,然后在每个HTTP请求中使用 session = Session()
,这样可以确保每次都能提供一个新的连接。
线程本地存储比较麻烦,它需要保存状态,这在不同的网络服务器线程模型中不太好用。最好保持无状态。比如,SqlAlchemy的文档提到,如果你在使用 scoped_session
,不要忘记调用 .remove()
。会有人记得这样做吗?
下面是来自 https://docs.sqlalchemy.org/en/14/orm/contextual.html#using-thread-local-scope-with-web-applications 的一段摘录:
按照上述流程,将Session与网络应用集成有两个要求:
在网络应用首次启动时创建一个单一的
scoped_session
注册表,确保这个对象可以被应用的其他部分访问。确保在网络请求结束时调用
scoped_session.remove()
,通常通过与网络框架的事件系统集成来建立一个“请求结束”事件。
在每个方法里使用Scoped_session会给你一个本地的会话,这个会话是你不能提前获取的(比如在模块级别)。其实在每个方法里都打开一个新会话并不是必要的,你可以使用一个全局会话。只有在全局会话不可用的时候,才创建一个新的会话。也就是说,你可以写一个方法来返回一个会话,并把它添加到你的包里的init.py文件中。
建议阅读文档:
scoped_session()
这个函数可以创建一个线程管理的会话对象注册表。它通常在网页应用中使用,这样就可以用一个全局变量安全地表示与一组对象相关的事务会话,而且这些会话是局限在单个线程中的。
简单来说,使用scoped_session()
可以确保线程安全。