我最近开始为我的项目使用Flask + Sqlalchemy,并且在关闭服务器一天后发现500个错误。我认为这是由于数据库会话超时导致的,但是我不确定。我们应该为每个请求创建一个新会话,还是Flask应用程序启动时一个会话?我在我的app.py顶部有这个
from sqlalchemy import Column, ForeignKey, Integer, String, create_engine, func, cast, Float
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import relationship,scoped_session,sessionmaker,aliased
engine = createengine(DB_PATH)
Session = sessionmaker(bind=engine)
session = Session()
app = Flask(name_)
Run Code Online (Sandbox Code Playgroud)
然后,对于视图中的所有查询,我都会执行以下操作:“ session.query(Table)...”这是错误的吗,我应该为每个端点调用都建立一个会话吗?
Nic*_*ady 12
接受的答案有一些问题,尽管不可否认它应该有效。
threading.local(). 虽然对于大多数应用程序来说都很好,但它忽略了被安装的可能性greenlet,在这种情况下本地线程 ID 是不够的。g. 正如评论中指出的,scoped_session已经处理了这部分。Flask 本身不管理线程,这是 WSGI 服务器的职责。适当地,根据文档,依赖线程范围不是存储数据库会话的推荐方法,尽管它应该可以正常工作,因为请求可能直接与线程关联。
特别是,虽然使用本地线程可能很方便,但最好将其直接与请求
Session关联,而不是与当前线程关联。因此,最好根据文档使用自定义范围,以便我们可以将会话直接与请求上下文相关联。这可以使用自定义创建的范围来完成。
来自 SQLAlchemy 文档的伪代码
from my_web_framework import get_current_request, on_request_end
from sqlalchemy.orm import scoped_session, sessionmaker
Session = scoped_session(sessionmaker(bind=some_engine), scopefunc=get_current_request)
@on_request_end
def remove_session(req):
Session.remove()
Run Code Online (Sandbox Code Playgroud)
对于 SQLAlchemy,附加会话的最干净的对象似乎是应用程序上下文,因为这是与请求直接关联的最高级别变量。这是有关 Flask 上下文如何工作的Flask 文档。您可以通过.AppContext实例访问内部LocalStack。这个 stackoverlow 答案指向相同的解决方案。该函数很有用,因为它要么返回线程 id,要么调用 greenlet 函数来提供可用的标识符(如果已安装)。也就是说,flask似乎确实使用本地线程本身来做很多事情。我搜索了又搜索,但找不到任何可以保证 WSGI 服务器(例如gunicorn 或 uwsgi)将为每个请求创建一个线程的内容。如果有人有这方面的资料,我很想看看。无论如何,推荐的方法是使用应用程序上下文,这在语义上比依赖与请求具有相同生命周期的线程更清晰。_app_ctx_stack_app_ctx_stack.__ident_func__
最后,另一条评论提到使用 Flask-SQLAlchemy。虽然这对于大多数项目来说是个好主意,但我认为它并不总是有意义。就我个人而言,我希望使用 SQLAlchemy 来定义我的模型定义,而不是通过 Flask-SQLAlchemy 来定义。我认为(就我而言)这些模型很可能在不久的将来在 Flask 之外使用。我也不想使用与 SQLAlchemy 不同的 API。时期。虽然我认为它们即使不完全相同,也可能非常相似,但它没有使用我不喜欢的 SQLAlchemy 本身。我回顾性地发现了一个来自towardsdatascience的博客,也得出了同样的结论。
综上所述,我的解决方案看起来与数据科学人员所做的几乎相同。我正在添加他们发布的存储库中的相关部分来执行此操作。
主要.py
from flask import Flask, _app_ctx_stack
from sqlalchemy.orm import scoped_session
from .database import SessionLocal, engine
app = Flask(__name__)
app.session = scoped_session(SessionLocal, scopefunc=_app_ctx_stack.__ident_func__)
@app.teardown_appcontext
def remove_session(*args, **kwargs):
app.session.remove()
Run Code Online (Sandbox Code Playgroud)
数据库.py
from sqlalchemy import create_engine
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker
SQLALCHEMY_DATABASE_URL = "sqlite:///./test.db"
# SQLALCHEMY_DATABASE_URL = "postgresql://user:password@postgresserver/db"
engine = create_engine(
SQLALCHEMY_DATABASE_URL, connect_args={"check_same_thread": False}
)
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
Base = declarative_base()
Run Code Online (Sandbox Code Playgroud)
这个主题非常复杂,所以我欢迎评论,我会更新答案,但希望这项研究对其他人有帮助。
在某些情况下,使用Flask-SQLAlchemy Extension可能不合适。例如,如果要在完全不同的Python模块中管理模型类和数据库连接详细信息,以供Flask之外的软件重用,则不需要/不需要扩展即可为您管理这些事情。
假设您拥有自己的代码以连接到数据库并Session通过类似的方式创建类(也engine提供了假设):
Session = scoped_session(sessionmaker(bind=engine))
Run Code Online (Sandbox Code Playgroud)
对于需要数据库连接的页面,您可以使用该对象创建一个会话实例:
from flask import g
def my_page():
session = Session()
g.my_db_session = session # save session in the request context
...
Run Code Online (Sandbox Code Playgroud)
我们需要删除创建的会话。这需要在my_page函数结束之后但响应结束之前完成。上面,我们g为此目的将会话保存在线程本地对象中。要在正确的时间删除它,请在创建Flask应用程序时添加以下代码:
@app.teardown_appcontext
def shutdown_session(exception=None):
''' Enable Flask to automatically remove database sessions at the
end of the request or when the application shuts down.
Ref: http://flask.pocoo.org/docs/patterns/sqlalchemy/
'''
if hasattr(g, 'my_db_session'):
g.my_db_session.remove()
Run Code Online (Sandbox Code Playgroud)
可能还有其他方法可以做到这一点,但这就是想法。请注意,SQLAlchemy为您提供了连接池。
我建议使用很棒的Flask SQLAlchemy 扩展来处理会话管理和连接池。此外,它还根据请求等处理会话的打开和关闭。
您可以查看相关的 SQLAlchemy 文档以获取更多详细信息:http://docs.sqlalchemy.org/en/latest/orm/session_basics.html#session-frequently-asked-questions。
来自文档:
一些 Web 框架包括帮助完成将会话的生命周期与 Web 请求的生命周期保持一致的任务的基础设施。这包括 Flask-SQLAlchemy(与 Flask Web 框架结合使用)和 Zope-SQLAlchemy(通常与 Pyramid 框架结合使用)等产品。SQLAlchemy 建议尽可能使用这些产品。
| 归档时间: |
|
| 查看次数: |
10335 次 |
| 最近记录: |