bigywater.tech
Flask · 89

Session Flush 与 Commit

flush 和 commit 到底差在哪?为什么没 commit 查询却看得到?批量写入应该怎么提交?这篇用第二个数据库连接当「别人」,把 flush 与 commit 的可见性和代价逐个量出来。

0 → 1
flush 之后与 commit 之后,另一个连接能看到的行数
18.6 ms
1000 个对象全部 add 后一次 commit 的耗时
RETURNING
PostgreSQL 上 INSERT 带回主键与 server_default

flush 与可见性

实测 · 本机执行输出
  add 之前主键 a.id = None
  add 之后、flush 之前 a.id = None
  flush 之后 a.id = 1,发了 1 条: ['INSERT INTO author (name) VALUES (%(name)s::VARCHAR) RETURNING author.id, author.created']
  此时另一个连接查询 author 表里 f1 的行数: 0 (本会话自己查询能看到)
  commit 之后另一个连接查询: 1

上一篇:SQLAlchemy Identity Map;下一篇:Rollback 的实际行为。

autoflush

实测 · 本机执行输出
  add 之后直接查询:count = 1(查询之前先发了 INSERT: ['INSERT INTO author (name) VALU…', 'SELECT count(*) AS count_1 FRO…'] )
  no_autoflush 里查询:count = 0(发了 ['SELECT'],INSERT 还没发)

server_default

实测 · 本机执行输出
  flush 之后 a.created 属性是否已加载: True | flush 发了 1 条 ['INSERT']
  访问 a.created → 再发 0 条 SELECT 去取;值的类型 datetime

顺序与批量

实测 · 本机执行输出
  把 3 本书(反序)加进 session 后 flush,SQL 顺序: ['author', 'book']
  100 个 Author 一次 flush:发了 1 条 SQL(psycopg 的 insertmanyvalues 批量插入)

flush 后 rollback

实测 · 本机执行输出
  flush 后 rollback,库里的 gone: 0

逐个与一次提交的代价

实测 · 本机执行输出
  每个对象都 flush                 150.9 ms
  每个对象都 commit                264.8 ms
  全部 add 后一次 commit            18.6 ms

数据库在本机、fsync 关闭,逐个 commit 的真实代价在生产环境里会大得多。

分步演示

Flush 与 Commit
本步的对象

    本文用到的工具与边界

    • 本机 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(非默认端口,fsync 关闭)
    • 没有验证:没有 RETURNING 的数据库(MySQL)上 server_default 的读取、eager_defaults 选项、bulk_insert_mappings 与 insert() 的 core 批量写入的耗时对比、flush 过程中的触发器与外键约束延迟
    京ICP备2026067502号-1京公网安备11010502063487号