bigywater.tech
Flask · 82

SQLAlchemy Session 生命周期

Session 里的对象有哪些状态?事务是什么时候开始、什么时候结束的?请求结束之后手里的对象还能不能用?这篇用真实的 PostgreSQL,把状态、连接状态和事件顺序逐个打印出来。

5 种
对象状态:transient、pending、persistent、deleted、detached
idle in transaction
执行 SQL 之后、commit/rollback 之前,PostgreSQL 里连接的状态
DetachedInstanceError
请求结束后读取没加载的关系或过期的属性时的异常

对象的状态

实测 · 本机执行输出
  Author(name=...)     → transient
  session.add(a)       → pending
  session.flush()      → persistent
  session.commit()     → persistent (expired)
  读取 a.name            → persistent
  session.delete(a)    → persistent
  flush()              → deleted
  commit()             → detached

上一篇:Flask-SQLAlchemy 初始化过程;下一篇:Flask 请求与数据库事务边界。

事务与连接

实测 · 本机执行输出
  动作               in_transaction  服务端连接状态
  一开始              False           idle
  执行了 select 1     True            idle in transaction
  commit()         False           idle
  再执行 select 1     True            idle in transaction
  rollback()       False           idle
  离开应用上下文之后(session.remove)服务端连接状态: idle

commit 的事件顺序

实测 · 本机执行输出
  add 之后 commit(): ['before_commit', 'before_flush', 'after_begin', 'after_flush', 'after_flush_postexec', 'after_commit']
  add + flush 然后 rollback(): ['before_flush', 'after_begin', 'after_flush', 'after_flush_postexec', '--', 'after_rollback', 'after_soft_rollback']

请求结束之后

实测 · 本机执行输出
  /change 只改了属性没 commit,请求结束后库里 bob 的名字: bob
  请求结束后拿着视图里的对象 keep[0] 的状态: detached
  读已加载的属性 keep[0].name → CHANGED
  读没加载过的关系 keep[0].books → DetachedInstanceError
  /commit 里 commit 之后对象状态: detached (expired)
  请求结束后读过期对象的属性 → DetachedInstanceError

close 与重新 add

实测 · 本机执行输出
  close() 前 persistent,close() 后 detached
  重新 session.add(a) 后 persistent
  session.identity_map 里的对象数: 1

分步演示

Session 生命周期
本步的对象

    本文用到的工具与边界

    • 本机 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(非默认端口)
    • 没有验证:autoflush 的细节(见第 89 篇)、嵌套事务与 savepoint、异步 Session、多线程共享同一个 Session 的后果、expire_on_commit 关掉之后的行为(见第 93 篇)
    京ICP备2026067502号-1京公网安备11010502063487号