快速入门 SQLAlchemy:Python ORM 基础
欢迎来到 SQLAlchemy 的世界!如果你是一位 Python 开发者,并且需要与数据库进行交互,那么 SQLAlchemy 几乎是你绕不开的选择。它是一款功能强大、灵活且成熟的数据库工具包和对象关系映射(ORM)库。本文将带你快速入门 SQLAlchemy 的基础知识,重点聚焦于其 ORM 部分,帮助你理解如何使用 Python 对象来操作数据库。
目录
- 引言:什么是 ORM?为什么选择 SQLAlchemy?
- ORM 的概念
- 为什么使用 ORM?
- SQLAlchemy 的优势
- 安装与准备
- SQLAlchemy 的核心组件概览
- Engine (引擎)
- MetaData (元数据)
- Table (表)
- Column (列)
- Core (核心) 与 ORM 的关系
- 使用 ORM:声明式模型 (Declarative)
- 定义数据库模型 (表映射到类)
- 数据类型映射
- 主键、外键、索引等约束
- 创建数据库和表结构
- 通过模型生成表
- 会话 (Session):ORM 的工作单元
- 理解 Session 的作用
- 创建 Session 工厂
- 使用 Session
- CRUD 操作 (增、删、改、查)
- 创建 (Create): 添加新数据
- 查询 (Read):
- 基础查询
- 过滤 (filter)
- 排序 (order_by)
- 限制结果数量 (limit, offset)
- 按主键获取
- 查询单个结果 (first, one, scalar)
- 更新 (Update): 修改现有数据
- 删除 (Delete): 移除数据
- 事务管理:提交与回滚
session.add()
,session.commit()
,session.rollback()
- 理解事务边界
- 关联关系 (Relationships)
- 一对多关系示例
- 定义
relationship()
- 通过关系访问数据
- 最佳实践:使用上下文管理器
- 总结与下一步
1. 引言:什么是 ORM?为什么选择 SQLAlchemy?
ORM 的概念
ORM,全称 Object-Relational Mapping(对象关系映射),是一种编程技术,用于在面向对象编程语言和关系型数据库之间转换数据。简单来说,ORM 允许你使用编程语言中的对象来代表数据库中的表和记录,通过操作这些对象来间接操作数据库。
想象一下,你的数据库里有一个 users
表,包含 id
, name
, email
等字段。在不使用 ORM 的情况下,你需要写 SQL 语句来查询、插入、更新或删除数据:
sql
SELECT id, name, email FROM users WHERE id = 1;
INSERT INTO users (name, email) VALUES ('Alice', '[email protected]');
UPDATE users SET email = '[email protected]' WHERE id = 1;
DELETE FROM users WHERE id = 1;
然后,在 Python 代码中,你需要执行这些 SQL 语句,并处理返回的结构化数据(通常是元组或字典)。
使用 ORM,你可以创建一个 User
类,它的实例对应于 users
表中的一行记录。操作数据就变成了操作 User
对象:
“`python
伪代码,使用 ORM 的概念
user = session.query(User).filter(User.id == 1).first() # 查询
new_user = User(name=’Alice’, email=’[email protected]’) # 创建
session.add(new_user)
session.commit() # 保存到数据库
“`
这种方式更加符合面向对象的思维,减少了直接编写和管理 SQL 的繁琐,提高了开发效率。
为什么使用 ORM?
- 抽象数据库细节: 你不需要关心底层数据库(MySQL, PostgreSQL, SQLite 等)的特定 SQL 语法差异,ORM 会为你处理。
- 提高开发效率: 使用面向对象的方式操作数据比拼接 SQL 字符串更直观、更快速。
- 代码更易维护: 模型定义集中,业务逻辑直接作用于对象,代码结构更清晰。
- 安全性: ORM 通常能帮助预防 SQL 注入等安全问题。
- 处理关联关系: ORM 擅长处理数据库表之间的复杂关联关系(一对一、一对多、多对多),使得通过对象属性就能访问关联的数据。
SQLAlchemy 的优势
SQLAlchemy 是 Python 世界中最流行和功能最强大的 ORM 之一。它的主要优势包括:
- 灵活性: SQLAlchemy 提供了两个主要的组件:Core 和 ORM。Core 提供了数据库抽象层和 SQL 构建表达式,你可以完全脱离 ORM,只使用 Core 来构建和执行 SQL。ORM 则在 Core 的基础上提供了对象映射能力。这意味着你可以根据需求选择不同层次的抽象,甚至在需要时混用 Core 和 ORM。
- 功能丰富: 支持几乎所有主流数据库,提供了强大的查询语言、事务管理、连接池、模式定义(Schema Definition Language, SDL)、迁移工具集成等。
- 高性能: SQLAlchemy 在性能方面表现优异,提供了延迟加载、积极加载等策略来优化数据加载效率。
- 成熟稳定: 拥有庞大的用户社区和活跃的开发,久经考验。
- 高度可配置: 提供了大量的配置选项,以满足各种复杂的场景需求。
对于刚入门的开发者来说,SQLAlchemy 的强大功能可能会让人觉得有点复杂。但一旦掌握了其核心概念,特别是 ORM 部分,你就能体会到它带来的便利和效率。本文将专注于 ORM 的基础,让你快速上手。
2. 安装与准备
在开始之前,你需要安装 SQLAlchemy。推荐使用 pip 工具进行安装。
bash
pip install SQLAlchemy
为了演示,我们还需要一个数据库驱动。SQLite 是一个轻量级的、基于文件的数据库,非常适合入门和测试,无需额外的服务器进程。Python 标准库自带了 SQLite 驱动。所以,只需要安装 SQLAlchemy 即可。
如果你想连接其他数据库,例如 PostgreSQL 或 MySQL,你需要安装相应的驱动:
- PostgreSQL:
pip install psycopg2-binary
- MySQL:
pip install PyMySQL
(或者mysql-connector-python
)
在本文中,我们将使用 SQLite 进行演示。
3. SQLAlchemy 的核心组件概览
虽然本文主要讲 ORM,但理解 SQLAlchemy Core 的几个基础概念对于理解 ORM 构建在哪上面是很有帮助的。
-
Engine (引擎): Engine 是数据库连接的入口点。它负责管理数据库连接池以及提供连接到数据库的能力。你可以通过一个 URL 来指定连接的数据库类型、地址、用户名、密码等信息。
“`python
from sqlalchemy import create_engineSQLite 数据库,文件名为 example.db
engine = create_engine(‘sqlite:///example.db’)
PostgreSQL 示例 (需要替换为你的连接信息)
engine = create_engine(‘postgresql://user:password@host:port/dbname’)
MySQL 示例 (需要替换为你的连接信息)
engine = create_engine(‘mysql+pymysql://user:password@host:port/dbname’)
“`
-
MetaData (元数据): MetaData 是一个容器对象,用于收集关于数据库模式(schema)的信息,比如表、列、约束等。你可以通过它来定义数据库结构,也可以通过它来反射(reflect)现有数据库的结构。
-
Table (表): Table 对象代表数据库中的一张表。它与 MetaData 关联,并包含 Column 对象来定义表的字段。
-
Column (列): Column 对象代表表中的一列。它与数据类型以及各种约束(如主键
primary_key=True
、非空nullable=False
、唯一unique=True
、默认值default
、索引index=True
等)关联。 -
Core (核心) 与 ORM 的关系: SQLAlchemy Core 提供了低层次的数据库操作能力,包括连接管理、SQL 表达式构建(例如
select([users_table.c.name])
)、事务管理。SQLAlchemy ORM 在 Core 之上构建,它将数据库表映射到 Python 类,将行映射到类的实例,将列映射到类的属性。ORM 通过 Session 来管理对象的生命周期和数据库同步。
在 ORM 中,我们通常使用声明式系统 (Declarative) 来定义模型,这个系统会自动为你创建 MetaData、Table 和 Column 对象,隐藏了部分 Core 的底层细节,使得定义模型更加简洁直观。
4. 使用 ORM:声明式模型 (Declarative)
SQLAlchemy 的声明式系统允许你将数据库表定义和 ORM 映射定义合二为一,通过简单的 Python 类来实现。这是现代 SQLAlchemy ORM 开发中最常用的方式。
定义数据库模型 (表映射到类)
首先,我们需要一个基类,它是所有声明式模型的基石。
“`python
from sqlalchemy.ext.declarative import declarative_base
Base = declarative_base()
“`
declarative_base()
返回一个基类,你的所有模型类都应该继承自它。这个基类会维护一个 MetaData 对象(可以通过 Base.metadata
访问),并知道如何将你的类映射到数据库表。
接下来,我们定义一个简单的 User
模型,对应数据库中的 users
表。
“`python
from sqlalchemy import Column, Integer, String
class User(Base):
tablename = ‘users’ # tablename 是必须的,指定了数据库中的表名
id = Column(Integer, primary_key=True) # 定义一个整型主键列
name = Column(String, nullable=False) # 定义一个字符串列,非空
email = Column(String, unique=True) # 定义一个字符串列,唯一
# 可选:用于打印对象时的友好表示
def __repr__(self):
return f"<User(id={self.id}, name='{self.name}', email='{self.email}')>"
“`
上面的代码定义了一个名为 User
的 Python 类,它继承自 Base
。通过 __tablename__
指定了它映射到数据库的 users
表。类属性 id
, name
, email
使用 Column
函数定义,映射到表中的同名列。
数据类型映射
SQLAlchemy 支持丰富的数据库数据类型,并且在不同的数据库后端之间进行抽象。常用的数据类型包括:
Integer
: 整型String(length)
: 变长字符串,通常需要指定最大长度length
Text
: 不限长度的文本Boolean
: 布尔型Date
: 日期DateTime
: 日期和时间Time
: 时间Float
: 浮点型Numeric(precision, scale)
: 定点十进制数LargeBinary
/Blob
: 二进制大对象
你可以根据数据库字段的类型选择合适的 SQLAlchemy 类型。
主键、外键、索引等约束
在 Column
定义中,你可以传递额外的参数来指定列的约束:
primary_key=True
: 将该列设为主键。nullable=False
: 将该列设为非空。unique=True
: 要求该列的值在表中唯一。default=value
: 设置该列的默认值。index=True
: 为该列创建索引,以加快查询速度。ForeignKey('tablename.columnname')
: 定义外键,关联到另一张表的某一列。需要导入ForeignKey
。
5. 创建数据库和表结构
定义好模型类后,我们需要将这些模型“翻译”成实际的数据库表。Base.metadata
包含了所有通过 Base
定义的模型信息。我们可以利用这个元数据对象,通过 Engine 来创建所有未创建的表。
“`python
假设我们已经有了 engine 对象,并且定义了 User 模型
from sqlalchemy import create_engine, Column, Integer, String
from sqlalchemy.ext.declarative import declarative_base
Base = declarative_base()
class User(Base): … (同上)
确保导入了 Base 和 engine
from your_models_file import Base # 如果模型定义在其他文件
from your_engine_setup import engine # 如果 engine 在其他地方创建
创建所有在 Base.metadata 中注册的表
checkfirst=True 表示创建前先检查表是否存在,如果存在则跳过
Base.metadata.create_all(engine, checkfirst=True)
print(“数据库表已创建或已存在。”)
“`
执行这段代码后,如果 example.db
文件不存在,它会被创建;如果文件存在但其中没有 users
表,那么 users
表会被创建。如果 users
表已经存在,则什么也不会发生(因为 checkfirst=True
)。
6. 会话 (Session):ORM 的工作单元
在 SQLAlchemy ORM 中,Session 是核心概念。Session 代表了一次与数据库的对话,它负责:
- 跟踪对象的状态: 哪些对象被修改了,哪些是新的,哪些将被删除。
- 构建 SQL 语句: 根据你对对象的操作,生成相应的
INSERT
,SELECT
,UPDATE
,DELETE
语句。 - 管理事务: 协调多个操作作为一个原子单元(事务),要么全部成功(提交
commit
),要么全部失败(回滚rollback
)。 - 提供查询接口: 使用
session.query()
来构建查询语句。
Session 本身并不是线程安全的,每个线程通常应该有自己的 Session。推荐的做法是使用 sessionmaker
创建一个 Session 工厂,然后每次需要时从工厂获取一个新的 Session 实例。
“`python
from sqlalchemy.orm import sessionmaker
创建一个 Session 工厂
bind 参数指定了 Session 要绑定的 Engine
SessionLocal = sessionmaker(bind=engine)
现在你可以通过 SessionLocal() 来获取一个 Session 实例
session = SessionLocal()
可以在这里进行数据库操作…
最后,关闭 Session
session.close()
“`
获取 Session 后,所有通过该 Session 进行的数据库操作都将在这个 Session 的上下文中进行,直到你提交、回滚或关闭它。
7. CRUD 操作 (增、删、改、查)
有了 Engine、Base 和 Session,我们就可以开始进行数据库的 CRUD 操作了。
创建 (Create):添加新数据
要向数据库中添加一条新记录,只需创建一个模型类的实例,设置好属性值,然后通过 session.add()
方法将其添加到 Session 中。最后,调用 session.commit()
将更改保存到数据库。
“`python
假设我们已经有了 SessionLocal 工厂
session = SessionLocal() # 获取 Session 实例
创建一个新的 User 对象
new_user = User(name=’Alice’, email=’[email protected]’)
将对象添加到 Session 中
session.add(new_user)
提交 Session,将对象保存到数据库
session.commit()
print(f”用户 {new_user.name} 已添加到数据库,ID 是 {new_user.id}”) # ID 在commit后通常会自动生成并填充到对象中
再次添加一个用户
another_user = User(name=’Bob’, email=’[email protected]’)
session.add(another_user)
session.commit()
print(f”用户 {another_user.name} 已添加到数据库,ID 是 {another_user.id}”)
可以一次添加多个对象
session.add_all([user1, user2, user3])
session.commit()
“`
注意,session.add()
只是将对象放到了 Session 的“暂存区”,更改尚未写入数据库。只有调用 session.commit()
后,SQLAlchemy 才会生成 INSERT
语句并执行,将数据持久化。
查询 (Read):
查询是 ORM 中最常用的操作。SQLAlchemy ORM 提供了强大的查询 API。我们使用 session.query()
方法,传入要查询的模型类。
“`python
假设我们已经添加了一些用户数据
查询所有用户
all_users = session.query(User).all()
print(“\n— 所有用户 —“)
for user in all_users:
print(user)
按主键查询单个用户
user_by_id = session.query(User).get(1) # get() 方法直接按主键查询
if user_by_id:
print(f”\n— ID 为 1 的用户 —“)
print(user_by_id)
过滤查询 (filter)
查询名字是 ‘Alice’ 的用户
alice = session.query(User).filter(User.name == ‘Alice’).first() # first() 返回第一个匹配项或 None
if alice:
print(f”\n— 名字是 Alice 的用户 —“)
print(alice)
查询 ID 大于 1 的用户
users_gt_1 = session.query(User).filter(User.id > 1).all()
print(f”\n— ID 大于 1 的用户 —“)
for user in users_gt_1:
print(user)
组合过滤条件 (使用 and_, or_)
from sqlalchemy import and_, or_
查询名字是 Bob 且 email 是 [email protected] 的用户
bob = session.query(User).filter(and_(User.name == ‘Bob’, User.email == ‘[email protected]’)).first()
if bob:
print(f”\n— 名字是 Bob 且 email 是 [email protected] 的用户 —“)
print(bob)
查询名字是 Alice 或 Bob 的用户
alice_or_bob = session.query(User).filter(or_(User.name == ‘Alice’, User.name == ‘Bob’)).all()
print(f”\n— 名字是 Alice 或 Bob 的用户 —“)
for user in alice_or_bob:
print(user)
使用 like 进行模糊匹配
users_with_example_email = session.query(User).filter(User.email.like(‘%@example.com’)).all()
print(f”\n— email 包含 @example.com 的用户 —“)
for user in users_with_example_email:
print(user)
排序 (order_by)
按名字升序排序
users_ordered_by_name = session.query(User).order_by(User.name).all()
print(“\n— 按名字升序排序的用户 —“)
for user in users_ordered_by_name:
print(user)
按 ID 降序排序
users_ordered_desc = session.query(User).order_by(User.id.desc()).all()
print(“\n— 按 ID 降序排序的用户 —“)
for user in users_ordered_desc:
print(user)
限制结果数量 (limit, offset)
获取前两个用户
first_two_users = session.query(User).limit(2).all()
print(“\n— 前两个用户 —“)
for user in first_two_users:
print(user)
跳过第一个,获取接下来的两个用户
next_two_users = session.query(User).offset(1).limit(2).all()
print(“\n— 跳过第一个,获取接下来的两个用户 —“)
for user in next_two_users:
print(user)
查询单个结果
first(): 返回第一个匹配项或 None
one(): 返回一个匹配项,如果没有匹配项或有多个匹配项则抛出异常
scalar(): 返回一个单列结果的第一个值,如果没有匹配项或有多个值则抛出异常
注意:使用 one() 和 scalar() 需要确保查询结果是唯一的或只有一个值
获取用户数量
user_count = session.query(User).count() # count() 返回结果数量
print(f”\n— 用户总数 —“)
print(user_count)
“`
查询方法通常是链式的,你可以将 filter()
, order_by()
, limit()
, offset()
等方法组合使用。
更新 (Update):修改现有数据
更新数据非常简单:先通过查询获取到要修改的对象,然后直接修改对象的属性值,最后调用 session.commit()
将更改保存到数据库。
“`python
假设我们要更新 ID 为 1 的用户的邮箱
user_to_update = session.query(User).get(1)
if user_to_update:
print(f”\n— 更新前用户 —“)
print(user_to_update)
user_to_update.email = '[email protected]'
# user_to_update.name = 'Alicia' # 可以修改多个属性
session.commit() # 提交更改
print(f"用户 ID 为 1 的邮箱已更新。")
print(user_to_update) # 对象属性已被更新
“`
在调用 session.commit()
之前,修改只存在于 Session 中。commit()
会检测所有被修改的对象,并生成相应的 UPDATE
语句执行。
删除 (Delete):移除数据
要删除数据,首先获取要删除的对象,然后使用 session.delete()
将其标记为待删除,最后调用 session.commit()
。
“`python
假设我们要删除 ID 为 2 的用户
user_to_delete = session.query(User).get(2)
if user_to_delete:
print(f”\n— 删除用户 —“)
print(user_to_delete)
session.delete(user_to_delete) # 将对象标记为删除
session.commit() # 执行删除操作
print(f"用户 ID 为 2 的用户已删除。")
验证是否删除
deleted_user = session.query(User).get(2)
print(f”尝试获取 ID 为 2 的用户: {deleted_user}”) # 应该返回 None
“`
session.delete()
只是将对象从 Session 中移除,并标记其在提交时应被删除。session.commit()
会生成 DELETE
语句并执行。
8. 事务管理:提交与回滚
Session 在内部管理着一个事务。你通过 session.add()
, session.delete()
, 修改对象属性等操作对 Session 进行更改,这些更改都暂存在 Session 中,尚未写入数据库。
session.commit()
: 提交当前事务。这会将 Session 中的所有挂起更改(添加、删除、修改)作为一个原子操作发送到数据库。如果所有操作都成功,数据就被永久保存。session.rollback()
: 回滚当前事务。这会撤销 Session 中所有尚未提交的更改,将 Session 的状态恢复到上次提交或开始时的状态,数据库中的数据不受影响。这常用于处理错误情况。session.close()
: 关闭 Session。释放与之关联的数据库连接。一个关闭的 Session 不能再进行操作。
重要概念:
- 事务的原子性: 事务中的所有操作要么全部成功,要么全部失败。如果在
commit()
过程中发生错误,SQLAlchemy 会自动回滚事务,确保数据库保持一致状态。 - Session 的生命周期: Session 应该是短lived(生命周期短)的。在一个请求、一个任务或一个函数执行的范围内创建 Session,完成数据库操作后立即提交或回滚,并关闭 Session。不要在整个应用程序生命周期中重用同一个 Session。
9. 关联关系 (Relationships)
关系型数据库的强大之处在于表之间的关联。ORM 的一个主要优势就是能够方便地处理这些关联,使得你可以通过对象属性来访问关联的对象或集合。
让我们添加一个 Article
模型,并与 User
模型建立一对多关系:一个用户可以发表多篇文章,一篇文章只能由一个用户发表。
首先,修改 User
模型,添加一个属性来表示该用户的所有文章:
“`python
from sqlalchemy import ForeignKey
from sqlalchemy.orm import relationship # 导入 relationship
class User(Base):
tablename = ‘users’
id = Column(Integer, primary_key=True)
name = Column(String, nullable=False)
email = Column(String, unique=True)
# 定义与 Article 的一对多关系
# 'Article' 是关联的模型类名
# backref='author' 在 Article 模型中创建一个 'author' 属性,指向关联的 User 对象
articles = relationship('Article', backref='author')
def __repr__(self):
return f"<User(id={self.id}, name='{self.name}')>" # 简化表示
“`
然后,创建 Article
模型,并添加一个外键列指向 users
表的主键,以及一个属性来表示关联的作者:
“`python
from sqlalchemy import Text
class Article(Base):
tablename = ‘articles’
id = Column(Integer, primary_key=True)
title = Column(String, nullable=False)
content = Column(Text)
# 定义外键列,关联到 users 表的 id 列
user_id = Column(Integer, ForeignKey('users.id'), nullable=False)
# backref='articles' 在 User 模型中创建了 articles 属性,我们不需要在这里再次定义 relationship
# author = relationship('User', backref='articles') # 这一行是可选的,如果 User 模型中已经定义了 backref='author'
def __repr__(self):
return f"<Article(id={self.id}, title='{self.title[:20]}...', user_id={self.user_id})>"
“`
重新创建表结构 (或者使用迁移工具,但入门阶段直接创建更简单)
因为我们添加了新的 Article
模型,需要重新创建表(或确保新表被创建)。如果 users
表已经存在,create_all
会跳过它,但会创建 articles
表。
“`python
确保导入了 Article 模型
from your_models_file import Article # 如果模型定义在其他文件
重新创建所有表(会先检查是否存在)
Base.metadata.create_all(engine, checkfirst=True)
print(“Article 表已创建或已存在。”)
“`
通过关系访问数据
定义好关系后,你可以像访问普通属性一样访问关联的对象或集合。
“`python
假设我们已经有了 SessionLocal 工厂和一些 User 和 Article 数据
添加一些文章
user1 = session.query(User).get(1) # 获取 ID 为 1 的用户 (Alice)
if user1:
article1 = Article(title=’SQLAlchemy Basics’, content=’…’, author=user1) # 通过 relationship 设置作者
article2 = Article(title=’ORM Concepts’, content=’…’, user_id=user1.id) # 或者通过外键设置
session.add_all([article1, article2])
session.commit()
print("添加了两篇文章。")
查询用户及其文章 (通过 relationship)
user_with_articles = session.query(User).get(1)
if user_with_articles:
print(f”\n— 用户 {user_with_articles.name} 的文章 —“)
# 访问 user.articles 属性,SQLAlchemy 会自动执行一次查询来加载这些文章(延迟加载)
for article in user_with_articles.articles:
print(f”- {article.title}”)
查询文章及其作者 (通过 relationship/backref)
article_with_author = session.query(Article).filter(Article.title == ‘SQLAlchemy Basics’).first()
if article_with_author:
print(f”\n— 文章 ‘{article_with_author.title}’ 的作者 —“)
# 访问 article.author 属性
print(f”作者: {article_with_author.author.name}”)
另一种方式通过外键查询
article_explicit_join = session.query(Article).filter(Article.title == ‘ORM Concepts’).first()
if article_explicit_join and article_explicit_join.user_id:
author_from_fk = session.query(User).get(article_explicit_join.user_id)
print(f”文章 ‘{article_explicit_join.title}’ 的作者 (通过外键查询): {author_from_fk.name}”)
“`
使用 relationship
极大地简化了跨表查询和数据访问。当你访问 user.articles
时,SQLAlchemy 会在幕后执行一个 SELECT * FROM articles WHERE user_id = ?
的查询。当你访问 article.author
时,它会执行 SELECT * FROM users WHERE id = ?
的查询。这种默认行为称为延迟加载 (Lazy Loading),它只在属性被访问时才去加载数据。对于一对多关系,user.articles
返回一个列表,而对于多对一关系(通过 backref
或单独定义 relationship
),article.author
返回单个对象或 None
。
10. 最佳实践:使用上下文管理器
手动管理 Session 的 close()
调用容易出错,特别是在代码中发生异常时。推荐使用 Python 的上下文管理器 (with
语句) 来确保 Session 在使用完毕后总是被正确关闭,即使发生错误也能回滚。
你可以为 sessionmaker
创建的 SessionLocal 添加一个函数,使其可以作为上下文管理器使用:
“`python
from sqlalchemy.orm import Session
… SessionLocal = sessionmaker(bind=engine) …
定义一个函数来获取 Session 并使用上下文管理器
def get_db():
db = SessionLocal()
try:
yield db # 生成 Session 实例
finally:
db.close() # 无论如何都关闭 Session
如何使用:
with get_db() as session:
# 在这里进行所有数据库操作,如查询、添加、修改、删除
users = session.query(User).all()
for user in users:
print(user)
# 如果需要提交,手动调用 commit()
# session.commit()
# Session 在 with 块结束时自动关闭
“`
在实际应用中,特别是 Web 框架(如 FastAPI 或 Flask)中,通常会集成这种模式,确保每个请求都有一个独立的、正确管理生命周期的数据库 Session。在一个 with
块中进行所有操作,并在块的最后统一 commit()
或 rollback()
(通常由框架处理异常自动回滚)。
11. 总结与下一步
恭喜你!通过阅读本文,你已经快速入门了 SQLAlchemy 的 ORM 基础知识,包括:
- ORM 的概念和 SQLAlchemy 的优势
- Engine 的作用
- 使用声明式系统定义模型 (表映射到类)
- 常见的数据类型和列约束
- 如何通过模型生成数据库表
- Session 作为 ORM 的工作单元
- 使用 Session 进行基本的 CRUD 操作 (添加、查询、更新、删除)
- 理解和管理事务 (commit, rollback)
- 定义和使用一对多关联关系 (
relationship
,ForeignKey
) - 使用上下文管理器管理 Session
这只是 SQLAlchemy 功能的冰山一角。接下来,你可以深入学习:
- 更复杂的查询: 连接 (Join)、分组 (Group By)、聚合函数 (Sum, Avg, Count 等)、子查询。
- 加载策略: 延迟加载 (Lazy Loading)、立即加载 (Eager Loading)、联合加载 (Joined Loading) 等,以优化查询性能。
- 多对多关系 的定义和使用。
- 继承映射: 如何将类继承结构映射到数据库表。
- SQLAlchemy Core: 学习如何直接使用 Core 来构建和执行 SQL 表达式,这在某些复杂或需要高性能的场景下非常有用。
- 数据库迁移工具: 如 Alembic,用于管理数据库模式随时间的变化。
- 连接池配置: 优化数据库连接的使用。
通过不断实践和深入学习,你将能够充分发挥 SQLAlchemy 的强大功能,更高效、更优雅地处理数据库交互任务。
现在,就开始动手编写代码,将这些知识应用到你的项目中吧!