Python 演示FastApi与sqlalchemy结合使用(异步模式)

  • 安装依赖
    annotated-types==0.7.0
    anyio==4.6.2
    asyncmy==0.2.10
    click==8.1.8
    exceptiongroup==1.3.0
    fastapi==0.116.1
    greenlet==3.1.1
    h11==0.16.0
    idna==3.10
    pydantic==2.10.6
    pydantic_core==2.27.2
    sniffio==1.3.1
    SQLAlchemy==2.0.43
    starlette==0.44.0
    typing_extensions==4.13.2
    uvicorn==0.33.0
  • 演示代码
    from contextlib import asynccontextmanager
    from typing import AsyncIterator
    
    from fastapi import Depends, FastAPI
    from sqlalchemy import BigInteger, Column, String, text
    from sqlalchemy.engine import URL
    from sqlalchemy.ext.asyncio import (
        AsyncAttrs,
        AsyncConnection,
        AsyncSession,
        async_sessionmaker,
        create_async_engine,
    )
    from sqlalchemy.orm import DeclarativeBase
    
    ################################################################################# 首先准备数据模型 ################################################################
    
    
    class Base(AsyncAttrs, DeclarativeBase):
        """
        ORM对象基类
        """
    
        pass
    
    
    class User(Base):
        """
        用户表
        """
    
        __tablename__ = "user"
    
        id = Column(BigInteger, primary_key=True, autoincrement=True)
        name = Column(String(20), nullable=False)
    
    
    ################################################################################# 创建数据库引擎 ################################################################
    
    
    # 创建连接uri
    db_uri = URL.create(
        "mysql+asyncmy",
        username="root",
        password="123456",
        host="localhost",
        port=3306,
        database="one",
    )
    
    # 指定连接参数
    connect_args = {
        "pool_size": 10,  # 连接池大小,保持10个空闲连接
        "max_overflow": 20,  # 最大溢出连接数,当连接池耗尽时最多创建20个额外连接
        "pool_timeout": 30,  # 连接超时时间,从连接池获取连接的等待时间(秒)
        "pool_recycle": 3600,  # 连接回收时间,1小时后自动回收连接防止数据库超时
        "pool_pre_ping": True,  # 连接前检测,确保从池中获取的连接是有效的
        "echo": True,  # 打印sql语句,生产环境设置为False
    }
    
    
    # 创建mysql引擎
    mysql_engine = create_async_engine(
        db_uri,
        **connect_args,
    )
    
    
    ################################################################################# 创建数据库和表方法 ################################################################
    
    
    async def create_db_and_tables():
        """
        根据数据模型创建数据库和表
        注意: 只负责创建,当数据模型字段的数据类型变更后,是不会自动修改表中对应列的数据类型的
        """
        async with mysql_engine.begin() as conn:
            await conn.run_sync(Base.metadata.create_all)
    
    
    ################################################################################# 绑定fastapi启动 ################################################################
    
    
    @asynccontextmanager
    async def lifespan(app: FastAPI):
        """
        fastapi服务上下文管理
        """
        # 启动逻辑
        await create_db_and_tables()
        yield
        # 关闭逻辑
    
    
    # 创建fastapi服务实例
    app = FastAPI(lifespan=lifespan)
    
    
    ################################################################################# 准备可以和fastapi Depends关联的工厂方法 ################################################################
    
    # 会话实例工厂
    session_factory = async_sessionmaker(
        bind=mysql_engine,
        class_=AsyncSession,
        expire_on_commit=False,  # 提交后不使对象过期,避免重复查询
        autoflush=False,  # 关闭自动刷新,手动控制刷新时机
    )
    
    
    async def get_conn() -> AsyncIterator[AsyncConnection]:
        """
        异步生成异步连接,用于执行原生SQL,不推荐使用
        结合Depends使用会在使用完后自动关闭连接
        """
        async with mysql_engine.connect() as conn:
            yield conn
    
    
    async def get_session() -> AsyncIterator[AsyncSession]:
        """
        异步生成异步会话实例,用于执行orm操作, 推荐使用
        结合Depends使用会在使用完后自动关闭会话
        """
        async with session_factory() as session:
            yield session
    
    
    ################################################################################# 路由中使用会话/连接 ################################################################
    
    
    @app.get("/add_user1")
    async def add_user1(*, session: AsyncSession = Depends(get_session)):
        """
        通过会话操作演示
        """
        user = User(name="cjtarrr1")
        async with session.begin():
            # 开启自动提交/回滚的事务
            session.add(user)
        return {"id": user.id, "name": user.name}
    
    
    @app.get("/add_user2")
    async def add_user2(*, conn: AsyncConnection = Depends(get_conn)):
        """
        通过底层连接操作演示
        """
        async with conn.begin():  # 自动事务管理
            query = text("INSERT INTO user(name) VALUES(:name)")
            result = await conn.execute(query, {"name": "cjtarrr2"})
            inserted_id = result.lastrowid  # MySQL获取插入ID的方式
            # 退出上下文时自动提交,出错时自动回滚
    
        return {"id": inserted_id, "name": "cjtarrr2"}
    
    
    if __name__ == "__main__":
        import uvicorn
    
        uvicorn.run(app, host="127.0.0.1", port=10002)

     


     

posted @ 2025-08-28 15:30  CJTARRR  阅读(41)  评论(0)    收藏  举报