You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

FastAPI项目中db.py代码先于startup事件执行的问题解决

解决FastAPI启动时数据库引擎早于密钥加载的问题

方案一:懒加载单例引擎(推荐)

修改db.py,将引擎初始化逻辑封装为懒加载函数,确保只创建一次引擎,且首次调用时环境变量已完成加载:

import os
from sqlmodel import create_engine, Session
from sqlalchemy.engine import URL

# 初始化引擎变量为None
_engine = None

def get_engine():
    global _engine
    if _engine is None:
        connection_string = 'DRIVER={};SERVER={};DATABASE={};UID={};PWD={}'.format(
            os.getenv('DRIVER'), 
            os.getenv('SERVER'), 
            os.getenv('DB'), 
            os.getenv('USERNAME'), 
            os.getenv('PASSWORD')
        )
        connection_url = URL.create("mssql+pyodbc", query={"odbc_connect": connection_string})
        _engine = create_engine(connection_url)
    return _engine

# 生成数据库会话的复用函数
def get_session():
    with Session(get_engine()) as session:
        yield session

在路由或其他需要数据库操作的代码中,通过get_session()获取会话即可:

from db import get_session
from fastapi import Depends

@router.get("/items")
def read_items(session: Session = Depends(get_session)):
    # 此处使用session执行数据库操作
    pass

该方案无需修改main.py的启动逻辑,引擎会在首次被调用时创建,此时startup事件已执行完毕,密钥已加载到环境变量中。

方案二:在Startup事件中初始化引擎并绑定到应用状态

如果希望引擎在启动阶段就完成初始化,可按以下步骤修改:

  1. 修改db.py,预留引擎变量及初始化函数:
import os
from sqlmodel import create_engine, Session
from sqlalchemy.engine import URL

engine = None

def init_engine():
    global engine
    connection_string = 'DRIVER={};SERVER={};DATABASE={};UID={};PWD={}'.format(
        os.getenv('DRIVER'), 
        os.getenv('SERVER'), 
        os.getenv('DB'), 
        os.getenv('USERNAME'), 
        os.getenv('PASSWORD')
    )
    connection_url = URL.create("mssql+pyodbc", query={"odbc_connect": connection_string})
    engine = create_engine(connection_url)

def get_session():
    with Session(engine) as session:
        yield session
  1. 修改main.py的启动事件,加载密钥后立即初始化引擎:
# ... 其他导入代码 ...
from db import init_engine

@app.on_event("startup")
def startup_event():
    load_secrets()
    init_engine()  # 密钥加载完成后初始化数据库引擎
# ... 其他代码 ...

这样引擎会在startup阶段完成初始化,后续所有使用db.engine或get_session()的地方都会复用同一个实例。

问题根源

原代码中db.py的引擎创建逻辑在模块被导入时(比如main.py或路由文件引用db模块)就会执行,而FastAPI的@app.on_event("startup")事件是在应用启动完成后才触发的,此时模块导入已完成,但密钥还未加载,导致os.getenv()返回None,最终引发错误。

内容的提问来源于stack exchange,提问作者configure.ng

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.19 00:28:09