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

FastAPI+SQLAlchemy遇UnboundExecutionError错误的解决求助

解决FastAPI + SQLAlchemy的UnboundExecutionError错误

错误原因

你遇到的sqlalchemy.exc.UnboundExecutionError核心问题在于会话管理方式错误:

  1. managers.py中直接导入并实例化sqlalchemy.orm.Session,这个会话没有绑定你在main.py中配置的数据库引擎;
  2. 你在PlayerManager的__init__中创建了一个会话实例,然后重复用with语句尝试复用它,导致会话被关闭后仍被调用,引发绑定缺失问题。

修复方案

步骤1:修改main.py,传递绑定好的sessionmaker

将main.py中创建的已绑定引擎的Session(sessionmaker实例)传递给PlayerManager,确保manager使用正确的会话工厂:

from fastapi import FastAPI
from sqlalchemy import create_engine, URL
from sqlalchemy.orm import sessionmaker
from models import Base
from typing import List
from schemas import Player, PlayerInfo
from managers import PlayerManager

url = URL.create(
    drivername="postgresql",
    host="localhost",
    port=5432,
    database="casino_player",
    username="postgres",
    password="postgres"
)

engine = create_engine(url)
Base.metadata.create_all(engine)

# 已绑定引擎的sessionmaker实例
Session = sessionmaker(bind=engine)

app = FastAPI(title="Casino Players", version="1.0.0")

# 将sessionmaker传递给PlayerManager
player_manager = PlayerManager(Session)

# ... 后续路由代码保持不变

步骤2:重构managers.py的会话逻辑

修改PlayerManager,使用传入的sessionmaker创建会话,确保每次操作使用独立的有效会话,同时避免跨会话操作实例:

from typing import List, Type
from fastapi import HTTPException
from models import CasinoPlayer
from schemas import Player, PlayerInfo


class PlayerManager:
    def __init__(self, session_class):
        # 保存绑定好引擎的sessionmaker类
        self.session_class = session_class

    def add_player(self, player: Player) -> CasinoPlayer:
        # 每次操作创建新会话
        with self.session_class() as session:
            db_player = CasinoPlayer(
                name=player.name, 
                win_value=player.win_value, 
                casino_name=player.casino_name
            )
            session.add(db_player)
            session.commit()
            # 刷新实例,获取数据库自动生成的id
            session.refresh(db_player)
            return db_player

    def get_player(self, player_id: int) -> Type[CasinoPlayer]:
        with self.session_class() as session:
            try:
                return session.query(CasinoPlayer).filter_by(id=player_id).one()
            except Exception:
                raise HTTPException(status_code=404, detail="Гравця з таким ID не знайдено")

    def get_all_players_info(self) -> List[PlayerInfo]:
        with self.session_class() as session:
            players_info_list = []
            players_records = session.query(CasinoPlayer).all()
            for player in players_records:
                win_value_formatted = f"{player.win_value} $"
                players_info_list.append(PlayerInfo(
                    id=player.id, 
                    name=player.name, 
                    win_value=win_value_formatted, 
                    casino_name=player.casino_name
                ))
            return players_info_list

    def update_player(self, player_id: int, new_name: str, new_win_value: float, new_casino_name: str):
        with self.session_class() as session:
            # 直接在当前会话中查询实例,避免跨会话操作
            db_player = session.query(CasinoPlayer).filter_by(id=player_id).one()
            db_player.name = new_name
            db_player.win_value = new_win_value
            db_player.casino_name = new_casino_name
            session.commit()

    def delete_player(self, player_id: int):
        with self.session_class() as session:
            db_player = session.query(CasinoPlayer).filter_by(id=player_id).one()
            session.delete(db_player)
            session.commit()

    def delete_all_players(self) -> int:
        with self.session_class() as session:
            # 使用批量删除,更高效
            num_deleted = session.query(CasinoPlayer).delete()
            session.commit()
            return num_deleted

关键优化点说明

  • 会话绑定正确:现在所有会话都通过main.py中绑定了引擎的sessionmaker创建,确保会话与数据库引擎关联;
  • 避免跨会话操作:update_player和delete_player不再调用get_player(会创建新会话),直接在当前会话中查询实例,避免实例属于不同会话导致的绑定错误;
  • 批量删除优化:delete_all_players使用query.delete()批量删除,比循环删除更高效;
  • 刷新实例:add_player中添加session.refresh(db_player),确保返回的实例包含数据库自动生成的id字段。

内容的提问来源于stack exchange,提问作者Anton Anpilohov

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.22 20:25:54