MySQL 8.0 与数据持久化基础
本手册的数据库学习路线
数据库部分统一使用 MySQL 8.0 + Tortoise ORM。这一章先认识 MySQL 和基本 SQL;第 26~41 章详细学习 ORM。建议顺序:第 15 章 → 第 26、27 章 → 第 28~32 章 → 三种关系 → 事务 → 完整接口与测试。
MySQL 是独立运行的数据库服务器,Tortoise 是 Python 程序与数据库之间的 ORM 工具。安装一个 Python 包不会自动安装或启动 MySQL 服务。
客户端请求
↓
FastAPI 路由函数
↓ await
Tortoise ORM:把操作组织成 SQL
↓
asyncmy:负责异步数据库通信
↓
MySQL 8.0:真正保存、查询和约束数据数据库的基本概念
| 概念 | 通俗解释 | 任务项目中的例子 |
|---|---|---|
| 数据库 | 一组相关表的容器 | fastapi_learning |
| 表 | 按统一结构保存记录 | todos |
| 行 | 一条记录 | 一条待办任务 |
| 列 | 一种属性 | title、done |
| 主键 | 唯一定位一行 | id |
| 外键 | 指向另一张表的记录 | owner_id 指向用户 |
| 唯一约束 | 不允许重复值或重复组合 | 用户名不能重复 |
| 索引 | 帮助某些查询快速定位数据 | 用户编号和完成状态的联合索引 |
| 事务 | 多个修改作为一个整体完成 | 转账中的扣款和入账 |
| 连接池 | 准备并复用有限数量的连接 | 省去每次从零建立连接 |
准备 MySQL 8.0
已经安装并运行 MySQL 8.0 可以跳过安装。尚未安装时,按 MySQL 8.0 官方 Windows 安装说明 安装对应版本的 Server,记下管理员密码与端口。
命令行客户端和 Workbench 是操作工具;真正保存数据的是 Server。安装 Workbench 并不代表 Server 已经安装。
在 PowerShell 中登录本机数据库:
mysql -h 127.0.0.1 -P 3306 -u root -p-P 是端口,-p 是交互输入密码。若 mysql 命令找不到,使用实际安装目录中的 mysql.exe,或配置其 bin 路径。
进入 MySQL 后执行以下 SQL,不要直接粘贴到 PowerShell:
SELECT VERSION();
SELECT @@default_storage_engine, @@character_set_server, @@collation_server;版本结果应为 8.0.x。本手册要求的是 8.0,不能仅因某个镜像叫 mysql:8 就认定它是 8.0;实际版本需要查询确认。
创建学习数据库与专用账号
在管理员连接中执行;先将示例密码替换成自己的密码:
CREATE DATABASE fastapi_learning
CHARACTER SET utf8mb4
COLLATE utf8mb4_0900_ai_ci;
CREATE USER 'fastapi_user'@'127.0.0.1'
IDENTIFIED BY 'ReplaceWithYourOwnStrongPassword';
GRANT SELECT, INSERT, UPDATE, DELETE,
CREATE, ALTER, DROP, INDEX, REFERENCES
ON fastapi_learning.* TO 'fastapi_user'@'127.0.0.1';如果库或账号已经存在,不要重复创建;确认原来的配置。账号由“用户名 + 允许来源主机”共同识别。容器、远程机器和本机可能被 MySQL 识别为不同来源,需要按实际连接来源授权。MySQL 建库说明、MySQL 账号说明
这里给学习账号提供了建表权限,方便初次实验。正式项目可以把运行账号与执行迁移的账号分开,运行账号只获得所需数据操作权限。
再用应用账号连接,验证自己确实能访问学习库:
mysql -h 127.0.0.1 -P 3306 -u fastapi_user -p fastapi_learning字符集与排序规则
utf8mb4 可以保存中文和完整 Unicode 字符;utf8mb4_0900_ai_ci 是本示例选择的排序规则,其中 ci 表示比较通常不区分大小写,ai 表示通常不区分重音。MySQL 8.0 字符集说明
因此,唯一用户名 alice 与 Alice 在这种规则下可能冲突。字符串匹配是否区分大小写,也不能只凭 Python 字符串的行为推断。需要严格区分时,应按业务选择适当的列级排序规则并通过迁移应用。
先亲手完成一次 SQL 增删改查
在学习库中新建一张独立演示表,它不与后面的 ORM 表同名:
CREATE TABLE demo_notes (
id INT PRIMARY KEY AUTO_INCREMENT,
title VARCHAR(100) NOT NULL,
done BOOLEAN NOT NULL DEFAULT FALSE
) ENGINE=InnoDB;
INSERT INTO demo_notes (title) VALUES ('学习 MySQL 8.0');
SET @demo_id = LAST_INSERT_ID();
SELECT id, title, done FROM demo_notes WHERE id = @demo_id;
UPDATE demo_notes SET done = TRUE WHERE id = @demo_id;
SELECT id, title, done FROM demo_notes WHERE id = @demo_id;
DELETE FROM demo_notes WHERE id = @demo_id;
SELECT id, title, done FROM demo_notes WHERE id = @demo_id;@demo_id 是当前连接里的变量;LAST_INSERT_ID() 读取刚生成的自增编号。最后一次查询返回空结果,因为这一行已删除。
| SQL | 在做什么 | 后面对应的 ORM 思路 |
|---|---|---|
INSERT | 新增记录 | await Model.create(...) |
SELECT | 查询记录 | await Model.filter(...) |
UPDATE | 修改记录 | await Model.filter(...).update(...) |
DELETE | 删除记录 | await Model.filter(...).delete() |
ORM 让你少写重复 SQL,但数据库的主键、外键、索引与事务仍然需要理解。
持久化与事务要分清
持久化回答“程序重启后数据是否还在”;事务回答“相关修改是否一起完成”。Tortoise 常规写操作通常按连接的自动提交行为完成;多步骤操作用 in_transaction() 明确组织,第 37 章会演示。
本示例使用 InnoDB,它支持事务和外键。创建表时可以通过 SHOW CREATE TABLE 表名 核对存储引擎和约束。MySQL InnoDB 表说明
学习时经常遇到的连接问题
| 问题 | 优先检查 |
|---|---|
| 连接拒绝或超时 | 服务是否启动、主机和端口是否正确 |
Access denied | 用户、密码、允许来源主机是否匹配 |
Unknown database | 是否先创建了配置中的数据库 |
| 中文或 emoji 出错 | 库、表、列、客户端连接的字符集 |
| Python 程序重启后“查不到数据” | 是否连到了同一个库,是否有事务回滚 |
| 能连接但无法建表 | 账号是否有建表及相关权限 |
本章练习
创建学习库和账号,确认版本为 8.0.x;完成演示 SQL;重新连接后确认表仍然存在。
过关标准:能解释 MySQL 服务、连接参数、数据库、表、主键、外键和 ORM 分别是什么。