FastAPI与MySQL数据库连接实战指南
1. FastAPI与MySQL数据库连接实战指南在当今的Web开发领域FastAPI凭借其出色的性能和易用性已经成为Python后端开发的首选框架之一。而MySQL作为最流行的关系型数据库之一与FastAPI的结合能够为开发者提供强大的数据存储和查询能力。本文将带你从零开始构建一个完整的FastAPI项目实现与MySQL数据库的无缝对接。1.1 为什么选择FastAPIMySQL组合FastAPI的异步特性与MySQL的高性能相得益彰。根据2023年的开发者调查报告FastAPI在Python Web框架中的满意度高达89%而MySQL在关系型数据库中的市场份额达到43.5%。这种组合特别适合需要快速开发、高性能和强类型检查的中大型项目。2. 环境准备与项目搭建2.1 基础环境配置首先确保你的开发环境已经安装以下组件Python 3.8MySQL 8.0虚拟环境工具推荐使用venv或conda创建项目目录并初始化虚拟环境mkdir fastapi-mysql-demo cd fastapi-mysql-demo python -m venv venv source venv/bin/activate # Linux/Mac venv\Scripts\activate # Windows2.2 安装必要依赖安装FastAPI和相关数据库驱动pip install fastapi uvicorn sqlalchemy pymysql python-dotenv这里我们选择pymysql作为MySQL驱动它比mysql-connector-python有更好的性能和兼容性。2.3 MySQL数据库准备在MySQL中创建数据库和用户CREATE DATABASE fastapi_demo CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; CREATE USER fastapi_user% IDENTIFIED BY your_strong_password; GRANT ALL PRIVILEGES ON fastapi_demo.* TO fastapi_user%; FLUSH PRIVILEGES;注意生产环境中应该使用更严格的权限控制和更强的密码策略3. 项目结构与核心配置3.1 项目目录结构建议采用以下项目结构fastapi-mysql-demo/ ├── .env # 环境变量 ├── app/ │ ├── __init__.py │ ├── main.py # 应用入口 │ ├── database.py # 数据库配置 │ ├── models/ # 数据模型 │ ├── schemas/ # Pydantic模型 │ └── routers/ # 路由模块 └── requirements.txt3.2 数据库连接配置在app/database.py中配置数据库连接from sqlalchemy import create_engine from sqlalchemy.ext.declarative import declarative_base from sqlalchemy.orm import sessionmaker import os from dotenv import load_dotenv load_dotenv() DATABASE_URL fmysqlpymysql://{os.getenv(DB_USER)}:{os.getenv(DB_PASSWORD)}{os.getenv(DB_HOST)}:{os.getenv(DB_PORT)}/{os.getenv(DB_NAME)} engine create_engine( DATABASE_URL, pool_size20, max_overflow10, pool_pre_pingTrue, pool_recycle3600 ) SessionLocal sessionmaker(autocommitFalse, autoflushFalse, bindengine) Base declarative_base()在.env文件中配置数据库连接信息DB_USERfastapi_user DB_PASSWORDyour_strong_password DB_HOSTlocalhost DB_PORT3306 DB_NAMEfastapi_demo4. 数据模型与CRUD实现4.1 定义基础模型在app/models/base.py中创建基础模型类from sqlalchemy.ext.declarative import as_declarative, declared_attr as_declarative() class Base: declared_attr def __tablename__(cls) - str: return cls.__name__.lower()4.2 创建业务模型以用户模型为例在app/models/user.py中from sqlalchemy import Column, Integer, String from .base import Base class User(Base): id Column(Integer, primary_keyTrue, indexTrue) username Column(String(50), uniqueTrue, indexTrue) email Column(String(100), uniqueTrue, indexTrue) hashed_password Column(String(255)) full_name Column(String(100), nullableTrue) is_active Column(Boolean, defaultTrue)4.3 实现CRUD操作在app/crud/user.py中from sqlalchemy.orm import Session from .models import User from .schemas import UserCreate def get_user(db: Session, user_id: int): return db.query(User).filter(User.id user_id).first() def get_user_by_email(db: Session, email: str): return db.query(User).filter(User.email email).first() def create_user(db: Session, user: UserCreate): fake_hashed_password user.password notreallyhashed db_user User( emailuser.email, hashed_passwordfake_hashed_password, full_nameuser.full_name ) db.add(db_user) db.commit() db.refresh(db_user) return db_user5. 路由与API端点实现5.1 创建用户路由在app/routers/users.py中from fastapi import APIRouter, Depends, HTTPException from sqlalchemy.orm import Session from .. import crud, schemas from ..database import SessionLocal router APIRouter(prefix/users, tags[users]) # 依赖项 def get_db(): db SessionLocal() try: yield db finally: db.close() router.post(/, response_modelschemas.User) def create_user(user: schemas.UserCreate, db: Session Depends(get_db)): db_user crud.get_user_by_email(db, emailuser.email) if db_user: raise HTTPException(status_code400, detailEmail already registered) return crud.create_user(dbdb, useruser) router.get(/{user_id}, response_modelschemas.User) def read_user(user_id: int, db: Session Depends(get_db)): db_user crud.get_user(db, user_iduser_id) if db_user is None: raise HTTPException(status_code404, detailUser not found) return db_user5.2 主应用文件在app/main.py中from fastapi import FastAPI from .routers import users from .database import engine, Base Base.metadata.create_all(bindengine) app FastAPI( titleFastAPI MySQL Demo, descriptionA demo project for FastAPI with MySQL, version0.1.0 ) app.include_router(users.router) app.get(/) def read_root(): return {message: Welcome to FastAPI MySQL Demo}6. 高级配置与优化6.1 数据库连接池优化在app/database.py中进一步优化连接池engine create_engine( DATABASE_URL, pool_size20, # 连接池保持的连接数 max_overflow10, # 连接池最大溢出连接数 pool_pre_pingTrue, # 每次使用前检查连接是否有效 pool_recycle3600, # 连接回收时间(秒) pool_timeout30, # 获取连接的超时时间 echoFalse # 是否输出SQL日志 )6.2 异步数据库支持FastAPI原生支持异步我们可以使用SQLAlchemy的异步版本pip install sqlalchemy[asyncio] asyncmy然后修改数据库配置from sqlalchemy.ext.asyncio import create_async_engine, AsyncSession from sqlalchemy.orm import sessionmaker ASYNC_DATABASE_URL fmysqlasyncmy://{os.getenv(DB_USER)}:{os.getenv(DB_PASSWORD)}{os.getenv(DB_HOST)}:{os.getenv(DB_PORT)}/{os.getenv(DB_NAME)} async_engine create_async_engine( ASYNC_DATABASE_URL, echoTrue ) AsyncSessionLocal sessionmaker( bindasync_engine, class_AsyncSession, expire_on_commitFalse )6.3 性能监控与日志添加性能监控中间件from fastapi import Request import time app.middleware(http) async def add_process_time_header(request: Request, call_next): start_time time.time() response await call_next(request) process_time time.time() - start_time response.headers[X-Process-Time] str(process_time) return response7. 安全最佳实践7.1 密码哈希处理使用passlib进行密码哈希pip install passlib[bcrypt]在用户模型中实现密码哈希from passlib.context import CryptContext pwd_context CryptContext(schemes[bcrypt], deprecatedauto) def verify_password(plain_password: str, hashed_password: str): return pwd_context.verify(plain_password, hashed_password) def get_password_hash(password: str): return pwd_context.hash(password)7.2 数据库迁移使用Alembic进行数据库迁移pip install alembic alembic init alembic配置alembic.ini和alembic/env.py后可以方便地进行数据库版本控制。8. 测试与部署8.1 单元测试使用pytest编写测试用例from fastapi.testclient import TestClient from sqlalchemy import create_engine from sqlalchemy.orm import sessionmaker from .main import app from .database import Base SQLALCHEMY_DATABASE_URL sqlite:///./test.db engine create_engine( SQLALCHEMY_DATABASE_URL, connect_args{check_same_thread: False} ) TestingSessionLocal sessionmaker(autocommitFalse, autoflushFalse, bindengine) Base.metadata.create_all(bindengine) def override_get_db(): try: db TestingSessionLocal() yield db finally: db.close() app.dependency_overrides[get_db] override_get_db client TestClient(app) def test_create_user(): response client.post( /users/, json{email: testexample.com, password: testpass} ) assert response.status_code 200 assert response.json()[email] testexample.com8.2 生产部署建议对于生产环境建议使用Gunicorn作为ASGI服务器配置Nginx作为反向代理使用Supervisor或Systemd管理进程配置HTTPS证书设置数据库主从复制启动命令示例gunicorn -w 4 -k uvicorn.workers.UvicornWorker app.main:app9. 常见问题与解决方案9.1 连接池耗尽问题症状频繁出现TimeoutError: QueuePool limit错误解决方案增加连接池大小确保每次操作后正确关闭会话使用try-finally块确保资源释放9.2 性能优化技巧使用selectinload或joinedload避免N1查询对频繁查询的字段添加索引使用Redis缓存热点数据考虑使用读写分离9.3 调试技巧设置echoTrue查看生成的SQL使用FastAPI的debug模式集成Sentry进行错误监控使用SQLAlchemy的事件系统记录慢查询10. 项目扩展方向添加JWT认证实现分页和过滤集成Celery处理异步任务添加OpenAPI文档扩展实现GraphQL接口构建Docker容器化部署通过以上步骤你已经成功构建了一个基于FastAPI和MySQL的完整Web API项目。这种架构不仅性能出色而且易于维护和扩展能够满足从简单应用到复杂系统的各种需求。