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)
- 独立连接池库:如
DBUtils、asyncpg自带的池等。通常我们通过 ORM 的内置机制处理即可。
- 关键配置要点
pool_size不宜过大,一般 CPU 核心数乘以 2~4 即可,太大只会浪费资源。- 设置
pool_pre_ping=True(SQLAlchemy),每次从池中取连接时先发一个探测包,避免使用已断开的连接。 - 记得在应用启动时初始化连接池,关闭时释放所有连接。
数据库交互是 Web 开发的基石,选对工具并正确配置连接池,可以让应用在高负载下依然稳定高效。通常的选择是:主流项目用 SQLAlchemy + Alembic 做迁移;小项目或脚本用 Peewee;无论哪种,上线前一定打开连接池并做好参数调优。