bigywater.tech
Flask · 81

Flask-SQLAlchemy 初始化过程

db = SQLAlchemy() 与 db.init_app(app) 到底做了什么?数据库是在什么时候连上的?SQLite 文件落在哪?连不上数据库什么时候才会知道?这篇用一个真实的 PostgreSQL 实例数连接数,把答案逐项量出来。

0
init_app 之后 PostgreSQL 上的连接数——Engine 创建了但没有连接
6.4 → 0.74 ms
第一次与第二次执行 SQL 的耗时(第一次要建立连接)
QueuePool / StaticPool
文件库与 sqlite 内存库的连接池类型

init_app 之后

实测 · 本机执行输出
  init_app 之前 PG 上的连接数: 0
  第一次 init_app 用时 56 ms(包含第一次导入 psycopg 等驱动),同一进程里再对另一个应用 init_app 只要 0.16 ms
  init_app 之后:0;app.extensions["sqlalchemy"] is db → True
  db.engine 的类型: Engine | 连接池: QueuePool (pool_size=5) | db.engines 的键: [None]
  访问 db.engine 之后连接数: 0
  第一次执行 SQL 之后连接数:1(第一次执行 6.4 ms)
  第二次执行 0.69 ms
  离开 app_context 之后连接数(session 被 remove,连接还给池,但池里仍保留): 1

上一篇:自定义 Flask Extension;下一篇:SQLAlchemy Session 生命周期。

SQLite 的文件

实测 · 本机执行输出
  init_app 之后 instance 目录存在: True | 文件: []
  engine.url: sqlite:///<tmp>/instance/app.db
  执行 SQL 之前文件存在: False
  执行 SQL 之后文件存在: True
  连接池类型: QueuePool
  sqlite 内存库的连接池: StaticPool

引擎配置项

实测 · 本机执行输出
  pool_size=2 max_overflow=1 pre_ping=True recycle=300
  db.engines 的键: ['other', None] | 绑定库的引擎: sqlite:///<实验目录>/instance/other.db

模型与 create_all

实测 · 本机执行输出
  还没 init_app 就定义了模型:db.metadata.tables = ['user'] | __tablename__ = user
  上下文外 create_all → Working outside of application context.
  create_all 之后 PG 里的表: user

重复 init_app 与 session 作用域

实测 · 本机执行输出
  同一个应用 init_app 两次 → A 'SQLAlchemy' instance has already been registered on this Flask app. Import and use that instance instead.
  同一个应用上下文里 db.session() 两次是同一个对象: True
  嵌套的新应用上下文里是不同的 session: True
  离开上下文后原 session 是否还在事务中 → False

错误出现的时机

实测 · 本机执行输出
  没有 URI → RuntimeError Either 'SQLALCHEMY_DATABASE_URI' or 'SQLALCHEMY_BINDS' must be set.
  未知方言的 URI 在 init_app 时就报错 → NoSuchModuleError Can't load plugin: sqlalchemy.dialects:nosuchdb
  端口没人监听的 PG URI:init_app 成功; 第一次执行 SQL 才报错 → OperationalError

分步演示

Flask-SQLAlchemy 初始化
本步的对象

    本文用到的工具与边界

    • 本机 macOS 27 arm64 / Python 3.14.7 / Flask 3.1.3 / Werkzeug 3.1.9 / Jinja2 3.1.6 / SQLAlchemy 2.1.1 / gunicorn 26.2.0(都装在自己的虚拟环境里);大多数实验用 Flask 的 test_client(直接调用 WSGI 应用,不经过网络),需要真实 HTTP 时另起 gunicorn 或开发服务器(端口 9600 以上,本机 127.0.0.1);计时用 time.perf_counter,数字每次运行会有小幅抖动。Flask-SQLAlchemy 3.1.1、psycopg 3.3.6、自己起的 PostgreSQL(非默认端口)
    • 没有验证:SQLALCHEMY_ECHO 的输出格式(见第 96 篇)、SQLALCHEMY_RECORD_QUERIES、MySQL 等其它方言、Flask-SQLAlchemy 与 SQLAlchemy 2.1.1 的兼容性在其它功能上的表现(本篇只覆盖上面列出的行为)
    京ICP备2026067502号-1京公网安备11010502063487号