db.session.execute()是Flask-SQLAlchemy执行原生SQL的直接入口,返回Result对象,需用text()包裹SQL并以字典传参,注意事务需显式管理、结果解析需匹配字段别名,避免SQL注入与性能陷阱。

SQLAlchemy的db.session.execute()是执行原生SQL最直接的方式
Flask-SQLAlchemy默认不鼓励写原生SQL,但真需要时,db.session.execute()就是入口。它返回一个Result对象(SQLAlchemy 2.0+),不是老版本的CursorResult或LegacyCursorResult——这点容易踩坑:如果你按旧文档用.fetchall()后还试图调用.keys(),会报AttributeError。
实操建议:
- 用
text()包裹SQL字符串,显式声明参数占位符(如:user_id),避免拼接字符串引发SQL注入 - 传参统一用字典,哪怕只一个参数,也别用元组——
execute(text("..."), {"id": 1})✅,execute(text("..."), (1,))❌(后者在新版本可能静默失败或行为异常) - 如果SQL有RETURNING子句(如PostgreSQL插入后返回ID),
execute()能直接拿到结果;但MySQL不支持RETURNING,得改用INSERT ...; SELECT LAST_INSERT_ID()组合
复杂查询含多表JOIN或窗口函数时,用db.session.execute()比ORM更可控
ORM在处理跨三张以上表、嵌套子查询、CTE(WITH语句)或窗口函数(ROW_NUMBER() OVER(...))时,可读性和调试成本陡增。这时候原生SQL反而清晰。
注意点:
立即学习“Python免费学习笔记(深入)”;
- 字段别名必须显式写出,不要依赖ORM自动映射;
execute()返回的是行元组或命名元组,字段顺序和别名要跟SQL里完全一致 - PostgreSQL的
json_agg()、MySQL的JSON_OBJECT()等聚合函数返回的是数据库原生类型,Python中可能是str或dict,取决于驱动和配置(如psycopg2默认把JSON转成dict,但pg8000可能返回str) - 若SQL含多个结果集(如存储过程返回多个SELECT),SQLite和MySQL的驱动通常只返回第一个;PostgreSQL需用
connection.execute(...).mappings().all()逐个取,且要确保连接未关闭
事务边界必须手动管理,db.session.execute()不自动加入当前ORM事务
这是最容易被忽略的一点:虽然都叫db.session,但execute()发出的语句默认不参与Flask-SQLAlchemy的session级事务控制。比如你在视图函数里先db.session.add()一条记录,再db.session.execute("UPDATE ..."),前者可能回滚,后者却已提交。
正确做法:
- 所有原生SQL操作,显式用
with db.session.begin():包裹,确保与ORM操作同事务 - 若SQL本身含
COMMIT或ROLLBACK(比如调用存储过程),务必确认数据库隔离级别和连接是否复用——Flask-SQLAlchemy的连接池可能让后续ORM操作看到未预期的中间状态 - 执行DDL(
CREATE TABLE、ALTER INDEX)时,某些数据库(如MySQL)会隐式提交当前事务,导致前面的ORM变更提前落库
批量插入/更新用executemany()而非循环execute()
面对上千条记录,用for item in data: db.session.execute(...)是性能黑洞。虽然db.session.executemany()存在,但它底层仍走单条语句发送,不如直连引擎高效。
更优解:
- 对PostgreSQL,优先用
connection.execute(text("INSERT INTO ... VALUES %s"), data)配合psycopg2.extras.execute_batch()或execute_values() - 对SQLite,用
connection.executemany()并开启PRAGMA journal_mode = WAL提升并发写入吞吐 - 无论如何,避免在循环里反复调用
db.session.commit()——每commit一次就是一次磁盘刷写,延迟飙升
原生SQL不是备选方案,而是补丁工具。越复杂的逻辑,越要警惕参数绑定方式、事务归属、结果解析这三个点——它们不出错时悄无声息,一出就是数据不一致。


















