Flask REST API中SQLAlchemy缓存导致资源删除重建后GET返回404问题
问题根源
你遇到的问题是全局复用SQLAlchemy Session导致的一级缓存(Identity Map)数据不一致,和日志里显示的SQL语句模板缓存没有关系(日志里的[cached since ...]是SQLAlchemy缓存了编译后的SQL模板,属于正常性能优化,不会缓存查询结果)。
SQLAlchemy的Session默认自带一级缓存,同一个Session生命周期内,相同查询条件的结果会被缓存,重复查询不会访问数据库。你在代码里把local_session定义成全局单例,所有请求共用同一个Session,同时Session本身不是线程安全的,在Flask多线程部署场景下本身就会存在数据错乱问题:
- 首次查询对应ISBN的图书不存在,Session缓存里就记录了该查询结果
- 执行DELETE操作提交事务后,全局Session没有被销毁
- 你重建图书时如果是通过其他Session/客户端操作,全局的单例Session感知不到数据库的变化
- 后续再用同一个Session查询该ISBN时,直接返回了缓存的“不存在”结果,就出现404。
解决方法
方案1:替换全局单例Session为SQLAlchemy提供的scoped_session(Web场景标准用法,推荐)
首先修改你db.py中的Session定义:
from sqlalchemy import create_engine from sqlalchemy.orm import sessionmaker, scoped_session engine = create_engine("你的数据库连接字符串") # 用scoped_session包装,保证每个线程/请求对应独立Session Session = scoped_session(sessionmaker(bind=engine))
然后在Flask中添加请求销毁钩子,每次请求结束后自动清除当前Session:
@app.teardown_appcontext def shutdown_session(exception=None): Session.remove()
最后删除Model层的全局local_session定义,所有数据库操作直接使用上面的Session对象即可,比如查询方法修改为:
def get_book_by_isbn(isbn): response = OperationResponseWrapper() try: response.payload = Session.query(Book).filter(Book.isbn == isbn).first() # 剩余逻辑保持不变
方案2:临时跳过缓存查询(适合不想改Session架构的场景)
直接在查询语句后添加populate_existing()方法,强制每次查询都走数据库拉取最新数据,忽略Session一级缓存:
response.payload = local_session.query(Book).filter(Book.isbn == isbn).populate_existing().first()
内容的提问来源于stack exchange,提问作者jbolt
相关产品推荐
相关产品推荐

