Flask-SQLAlchemy执行update后select返回未更新结果集问题求助
问题根因定位
该问题和MySQL的ACID特性无关,是Flask-SQLAlchemy的会话机制导致的,核心原因有两个:
1. 会话缓存未刷新
SQLAlchemy的ORM会话(Session)自带一级缓存,同一个会话内查询过的对象会默认保存在缓存中,后续对同一对象的查询会优先返回缓存内容,不会发起真实数据库请求:
- 如果你执行更新操作使用的
cur是独立于ORM会话的连接(比如直接从db.engine.connect()获取),更新操作属于另一个事务,ORM会话无法感知到该事务的修改,缓存中留存的还是旧对象 - 如果你执行更新操作使用的是当前ORM会话的连接,但用的是原生SQL语句而非ORM接口更新,SQLAlchemy也不会主动更新会话缓存中的对应对象
你直接查数据库能看到更新后的值,是因为更新操作的事务已经提交,数据库层面的修改已经持久化,只是ORM会话层没有同步最新值。
2. 事务未显式提交
Flask-SQLAlchemy默认会为每个请求隐式开启事务,所有DML(增删改)操作执行后必须显式调用db.session.commit()提交事务,修改才会对所有会话可见,如果未提交就直接查询,修改仅在当前事务内部可见,也可能出现读取旧值的情况。
修复方案
- 方案1:更新后提交事务并刷新缓存
在cur.execute(stmt)后补充提交事务和清空缓存的代码:cur.execute(stmt) db.session.commit() db.session.expire_all() # 清空当前会话的所有缓存,后续查询会直接拉取数据库最新值 - 方案2:使用ORM接口执行更新,自动同步缓存
先查询目标对象再修改属性,SQLAlchemy会自动追踪对象变更,无需手动处理缓存:try: combination = Combination.query.filter( Combination.sequence == sequence, Combination.subseq == subseq, Combination.languageId == lang_id ).first() if combination: combination.name = "yoga" if name is None else name combination.description = description combination.result = result combination.quality = quality combination.flag = flag db.session.commit() res['status'] = 'success' res["flag"] = combination.flag # 其余属性赋值保持不变 except exc.SQLAlchemyError: db.session.rollback() res['status'] = 'failed' - 方案3:查询时强制跳过缓存
如果不需要提交事务或者需要保留现有缓存,可在查询时添加populate_existing()参数强制读取数据库最新值:combination = Combination.query.filter( Combination.sequence == sequence, Combination.languageId == lang_id ).populate_existing().first()
补充说明
你观察到的现象和MySQL的ACID一致性并不冲突,一致性保证的是事务提交后数据的正确性和完整性,你遇到的是ORM框架层的缓存中间态问题,数据库层面的事务行为完全符合ACID规范。
内容的提问来源于stack exchange,提问作者Ayushman Srivastava Ayush
相关产品推荐
相关产品推荐

