asyncpg+PostgreSQL禁用缓存遇RuntimeWarning问题及正确实现方式
解决asyncpg+PostgreSQL禁用缓存及RuntimeWarning问题
先修复RuntimeWarning错误
你遇到的RuntimeWarning是因为engine.connect()是异步方法,必须先通过await获取连接对象,再调用execution_options。直接链式调用会导致协程未被执行,触发警告。
修正后的retrieve_data_from_db函数:
async def retrieve_data_from_db(query, engine): """ Connects to the database and returns the results by a given query """ # 先await获取连接对象,再设置执行选项 conn = await engine.connect() conn = conn.execution_options(compiled_cache=None) try: executed_query = await conn.execute(query) # 只读查询无需commit,写操作才需要 return executed_query except SQLAlchemyError as exc: print(exc) raise finally: await conn.close()
或者用async with的标准写法:
async def retrieve_data_from_db(query, engine): """ Connects to the database and returns the results by a given query """ raw_conn = await engine.connect() async with raw_conn.execution_options(compiled_cache=None) as conn: try: executed_query = await conn.execute(query) return executed_query except SQLAlchemyError as exc: print(exc) raise # async with会自动管理连接关闭,无需手动调用close
正确禁用各类缓存
要确保获取实时数据库结果,需要针对不同层级的缓存逐一禁用:
1. SQLAlchemy查询编译缓存
通过execution_options(compiled_cache=None)禁用,上面的修正代码已包含该设置。这个缓存用于存储SQLAlchemy编译后的查询语句,禁用后每次查询都会重新编译,确保适配最新的数据库元数据。
2. asyncpg预编译语句缓存
你在engine URL中设置prepared_statement_cache_size=0的方式是正确的,需确保参数格式无误:
engine = create_async_engine( f'postgresql+asyncpg://{username}:{password}@{host}/{database}?prepared_statement_cache_size=0', pool_pre_ping=True, echo=True, )
该参数会让asyncpg不缓存预编译的SQL语句,每次执行都直接发送原始SQL到PostgreSQL。
3. 事务隔离级别调整(确保实时读取)
PostgreSQL默认的READ COMMITTED隔离级别已能保证读取已提交的最新数据,但如果是长事务场景,可能会读取到事务启动时的快照数据。若需要强制获取最新数据:
- 确保每次查询都在新事务中执行(即每次查询都重新获取连接)
- 可以显式设置隔离级别:
conn = await engine.connect() conn = conn.execution_options( compiled_cache=None, isolation_level="READ COMMITTED" )
额外检查项
- 若使用SQLAlchemy Session,需设置
expire_on_commit=True,或在查询后手动调用session.expire_all(),避免Session缓存旧数据 - 排查应用层是否存在其他缓存(如本地内存缓存、Redis等),这些也会导致读取过期数据
内容的提问来源于stack exchange,提问作者Ani
相关产品推荐
相关产品推荐

