人人都会AI编程

19.3 数据库交互:SQLAlchemy ORM、Peewee、数据库连接池

更新时间:2026-07-12

Web 应用几乎离不开数据库。Python 生态里,直接写原生 SQL 当然可以,但大多数项目会使用 ORM(对象关系映射)来提升开发效率和代码可维护性。本节介绍两种主流方案:重量级的 SQLAlchemy 和轻量级的 Peewee,以及任意方案都绕不开的数据库连接池

SQLAlchemy ORM

SQLAlchemy 是 Python 生态里最成熟、最强大的数据库工具库,它提供了Core(底层 SQL 表达式语言)ORM(对象关系映射)两个层次,大多数 Web 开发直接使用 ORM 层。

  • 核心能力
  • 一次定义模型(Model),支持多种数据库:MySQL、PostgreSQL、SQLite 等切换几乎不改代码。
  • 自动建表、迁移(搭配 Alembic):模型变更后自动生成迁移脚本,再应用到数据库。
  • 关系映射:一对一、一对多、多对多用 Python 对象属性自然表达,关联查询自动生成 JOIN。
  • 惰性加载与预加载:支持 lazy='dynamic'joinedload() 等方式优化查询,避免 N+1 问题。
  • 会话(Session)管理:封装事务边界,提交、回滚、刷新等操作安全、统一。
  • 实际用法示例(Flask-SQLAlchemy 或纯 SQLAlchemy)
  from sqlalchemy import Column, Integer, String, ForeignKey
  from sqlalchemy.orm import declarative_base, relationship, Session

  Base = declarative_base()

  class User(Base):
      __tablename__ = 'users'
      id = Column(Integer, primary_key=True)
      name = Column(String(50))
      posts = relationship('Post', back_populates='author')

  class Post(Base):
      __tablename__ = 'posts'
      id = Column(Integer, primary_key=True)
      title = Column(String(100))
      user_id = Column(Integer, ForeignKey('users.id'))
      author = relationship('User', back_populates='posts')

  # 查询:获取某个用户的所有文章
  session = Session(engine)
  user = session.query(User).filter_by(name='张三').first()
  for post in user.posts:
      print(post.title)
  
  • 为什么用 SQLAlchemy
  • 适合大中型项目、需要复杂查询和灵活事务控制的场景。
  • 社区庞大,文档详尽,Django 的 ORM 虽然也好用,但 SQLAlchemy 是独立于框架的“行业标准”。
  • 可以自由选择使用 ORM 还是 Core 层拼 SQL,兼顾便捷性和性能。

Peewee

Peewee 是一个轻量级 ORM,设计哲学是“简单、直观”。如果项目较小,不需要 SQLAlchemy 的重量级特性,Peewee 能让你更快上手。

  • 特点
  • API 极其简洁:定义模型就像写普通类,查询语法接近自然语言。
  • 支持 SQLite、MySQL、PostgreSQL,基本满足大部分项目需求。
  • 自带轻量级迁移工具,可以自动检测模型变更并生成 SQL。
  • 源代码易读,扩展方便。
  • 快速示例
  from peewee import *

  db = SqliteDatabase('my_app.db')

  class User(Model):
      name = CharField()
      class Meta:
          database = db

  db.connect()
  db.create_tables([User])

  # 插入
  User.create(name='李四')

  # 查询
  for user in User.select().where(User.name == '李四'):
      print(user.name)
  
  • 选型建议
  • 小型项目、原型开发、个人工具或脚本,Peewee 足够好用,它没有厚重的学习成本。
  • 但如果项目未来可能变得复杂(多数据库、复杂关联、性能要求高),提前投入 SQLAlchemy 会更稳妥,因为它的生态和灵活性几乎是无限的。

数据库连接池

无论你使用 SQLAlchemy、Peewee 还是直接写 SQL,生产环境必须配置连接池。数据库连接是昂贵的资源,频繁创建/销毁连接会浪费性能和端口,还可能打满数据库允许的最大连接数。

  • 连接池的作用
  • 预先创建一批连接放在池中,请求来的时候直接取,用完归还,避免每次请求新建连接。
  • 控制最大连接数,防止后端流量突增导致数据库连接耗尽。
  • 自动检测和回收失效连接,保证池中连接始终可用。
  • 常见实现
  • SQLAlchemy 内置连接池:默认使用 QueuePool,可以通过 create_engine 的参数配置池大小、回收时间等。
    from sqlalchemy import create_engine

    engine = create_engine(
        'mysql+pymysql://user:pass@localhost/dbname',
        pool_size=10,        # 连接池保持的连接数
        max_overflow=20,     # 超过pool_size时允许创建的额外连接数
        pool_recycle=3600    # 连接最大存活时间,防止MySQL 8小时断开
    )
    
  • Peewee 连接池扩展:Peewee 本身不自带连接池,但可以配合 playhouse.pool 模块或 db_url 参数启用池化。
    from playhouse.pool import PooledSqliteDatabase
    db = PooledSqliteDatabase('my.db', max_connections=20)
    
  • 独立连接池库:如 DBUtilsasyncpg 自带的池等。通常我们通过 ORM 的内置机制处理即可。
  • 关键配置要点
  • pool_size 不宜过大,一般 CPU 核心数乘以 2~4 即可,太大只会浪费资源。
  • 设置 pool_pre_ping=True(SQLAlchemy),每次从池中取连接时先发一个探测包,避免使用已断开的连接。
  • 记得在应用启动时初始化连接池,关闭时释放所有连接。

数据库交互是 Web 开发的基石,选对工具并正确配置连接池,可以让应用在高负载下依然稳定高效。通常的选择是:主流项目用 SQLAlchemy + Alembic 做迁移;小项目或脚本用 Peewee;无论哪种,上线前一定打开连接池并做好参数调优。