13.后端开发基础
1. 数据库设计
1.1 为什么需要选择合适的数据类型?
问题:设计数据库表时,如何选择字段的数据类型?
生活类比:
- 用大箱子装小东西:浪费空间,搬运困难
- 用小箱子装大东西:装不下,需要换箱子
- 用合适的箱子:既不浪费,又能装下
实际例子:
1 | -- ❌ 不好的选择 |
选择合适数据类型的好处:
- ✅ 节省存储空间:数据量大的时候,节省的空间很可观
- ✅ 提高查询速度:数据类型越小,查询越快
- ✅ 避免数据错误:限制数据范围,防止无效数据
1.2 MySQL整数类型
1.2.1 整数类型对比
| 类型 | 字节 | 有符号范围 | 无符号范围 | 适用场景 |
|---|---|---|---|---|
| TINYINT | 1 | -128 ~ 127 | 0 ~ 255 | 年龄、状态码、是否删除 |
| SMALLINT | 2 | -32768 ~ 32767 | 0 ~ 65535 | 年份、小数量 |
| MEDIUMINT | 3 | -8388608 ~ 8388607 | 0 ~ 16777215 | 中等数量 |
| INT | 4 | -21亿 ~ 21亿 | 0 ~ 42亿 | 用户ID、文章ID(常用) |
| BIGINT | 8 | 超大范围 | 超大范围 | 超大数据量、时间戳 |
1.2.2 实际选型例子
用户ID(主键):
1 | -- ✅ 推荐:INT UNSIGNED |
年龄:
1 | -- ✅ 推荐:TINYINT UNSIGNED |
状态码:
1 | -- ✅ 推荐:TINYINT |
年份:
1 | -- ✅ 推荐:SMALLINT UNSIGNED |
数量(如库存、点赞数):
1 | -- 小数量(< 65535) |
1.3 MySQL字符串类型
1.3.1 定长字符串:CHAR
CHAR(n) = 固定长度的字符串,n为字符数(1-255)
特点:
- ✅ 固定长度,存储效率高
- ✅ 适合存储长度固定的数据
- ❌ 浪费空间(如果实际数据小于n)
实际例子:
1 | -- ✅ 适合用CHAR的场景 |
1.3.2 变长字符串:VARCHAR
VARCHAR(n) = 可变长度的字符串,n为最大字符数(1-65535)
特点:
- ✅ 按实际长度存储,节省空间
- ✅ 适合存储长度不固定的数据
- ❌ 需要额外1-2字节存储长度信息
实际例子:
1 | -- ✅ 适合用VARCHAR的场景 |
VARCHAR长度选择原则:
| 数据长度 | 推荐VARCHAR长度 | 说明 |
|---|---|---|
| 10-20字符 | VARCHAR(50) | 预留2-3倍空间,方便扩展 |
| 20-50字符 | VARCHAR(100) | 预留2倍空间 |
| 50-100字符 | VARCHAR(200) | 预留2倍空间 |
| 100-200字符 | VARCHAR(255) | 最大常用长度 |
1.4 MySQL文本类型
1.4.1 文本类型对比
| 类型 | 最大长度 | 存储空间 | 适用场景 |
|---|---|---|---|
| TINYTEXT | 255字符 | 1字节+实际长度 | 短文本、备注 |
| TEXT | 65,535字符(64KB) | 2字节+实际长度 | 文章内容、评论内容(常用) |
| MEDIUMTEXT | 16,777,215字符(16MB) | 3字节+实际长度 | 长文章、富文本内容 |
| LONGTEXT | 4,294,967,295字符(4GB) | 4字节+实际长度 | 超长文本、文档内容 |
1.4.2 实际选型例子
文章摘要/简介:
1 | -- ✅ 推荐:TINYTEXT或VARCHAR(255) |
文章内容:
1 | -- ✅ 推荐:TEXT |
富文本内容:
1 | -- ✅ 推荐:MEDIUMTEXT |
评论内容:
1 | -- ✅ 推荐:TEXT |
注意事项:
- ❌ 不要用VARCHAR存储长文本:VARCHAR最大65535字节,但实际受行大小限制
- ✅ 不确定长度时,选大不选小:TEXT不够用再升级到MEDIUMTEXT
- ✅ TEXT类型不能设置默认值:MySQL不支持
1.5 MySQL日期时间类型
1.5.1 日期时间类型对比
| 类型 | 格式 | 范围 | 存储空间 | 适用场景 |
|---|---|---|---|---|
| DATE | YYYY-MM-DD | 1000-01-01 ~ 9999-12-31 | 3字节 | 生日、日期 |
| TIME | HH:MM:SS | -838:59:59 ~ 838:59:59 | 3字节 | 时间点 |
| DATETIME | YYYY-MM-DD HH:MM:SS | 1000-01-01 00:00:00 ~ 9999-12-31 23:59:59 | 8字节 | 创建时间、更新时间(常用) |
| TIMESTAMP | YYYY-MM-DD HH:MM:SS | 1970-01-01 00:00:00 ~ 2038-01-19 03:14:07 | 4字节 | 自动更新时间戳 |
| YEAR | YYYY | 1901 ~ 2155 | 1字节 | 年份(节省空间) |
1.5.2 实际选型例子
创建时间、更新时间:
1 | -- ✅ 推荐:DATETIME |
生日:
1 | -- ✅ 推荐:DATE |
年份:
1 | -- ✅ 推荐:YEAR(如果只需要年份) |
DATETIME vs TIMESTAMP:
| 特性 | DATETIME | TIMESTAMP |
|---|---|---|
| 范围 | 1000-9999年 | 1970-2038年 |
| 存储空间 | 8字节 | 4字节 |
| 时区 | 不涉及时区 | 自动转换时区 |
| 推荐 | ✅ 大多数场景 | ⚠️ 需要时区转换时 |
1.6 MySQL其他常用类型
1.6.1 布尔类型
BOOLEAN / BOOL = TINYINT(1)的别名
实际例子:
1 | -- ✅ 推荐:TINYINT(1)或BOOLEAN |
1.6.2 浮点数类型
| 类型 | 精度 | 存储空间 | 适用场景 |
|---|---|---|---|
| FLOAT | 单精度 | 4字节 | 一般精度要求不高的浮点数 |
| DOUBLE | 双精度 | 8字节 | 高精度浮点数(常用) |
| DECIMAL(M,D) | 精确小数 | 变长 | 金额、价格(必须精确) |
实际例子:
1 | -- ✅ 价格、金额:必须用DECIMAL |
1.6.3 JSON类型
JSON = 存储JSON格式的数据(MySQL 5.7+)
实际例子:
1 | -- ✅ 适合存储灵活的配置、扩展字段 |
注意事项:
- ✅ 适合存储结构不固定的数据
- ❌ 不适合频繁查询的字段(查询性能较差)
- ✅
可以用JSON函数查询:
JSON_EXTRACT(config, '$.theme')
1.7 实际例子:博客系统表设计
用户表(users):
1 | CREATE TABLE users ( |
文章表(articles):
1 | CREATE TABLE articles ( |
评论表(comments):
1 | CREATE TABLE comments ( |
1.8 数据类型选择总结
选择原则:
- 够用即可:不要选择过大的类型,浪费空间
- 留有余地:不要选择过小的类型,避免后续扩展困难
- 考虑性能:数据类型越小,查询越快
- 考虑业务:根据实际业务需求选择
快速参考表:
| 数据 | 推荐类型 | 说明 |
|---|---|---|
| 主键ID | INT UNSIGNED | 大多数场景足够 |
| 年龄 | TINYINT UNSIGNED | 0-255足够 |
| 状态码 | TINYINT | -128~127足够 |
| 年份 | YEAR或SMALLINT UNSIGNED | YEAR最省空间 |
| 姓名 | VARCHAR(50) | 预留2-3倍空间 |
| 邮箱 | VARCHAR(100) | 通常20-50字符 |
| 标题 | VARCHAR(200) | 通常10-100字符 |
| 短文本 | TINYTEXT | < 255字符 |
| 文章内容 | TEXT | 大多数文章足够 |
| 长文章 | MEDIUMTEXT | 超长文章 |
| 创建时间 | DATETIME | 常用 |
| 生日 | DATE | 只需要日期 |
| 价格 | DECIMAL(10,2) | 必须精确 |
| 是否删除 | TINYINT(1) | 布尔值 |
2. API实现
2.1 为什么需要后端API?
前端和后端的分工:
| 角色 | 职责 |
|---|---|
| 前端 | 展示界面,处理用户交互 |
| 后端 | 处理业务逻辑,操作数据库 |
实际例子:
1 | 用户在前端点击"发布文章"按钮: |
2.2 使用FastAPI实现CRUD接口
2.2.1 FastAPI简介
FastAPI = 一个现代的Python Web框架,用于快速构建API
特点:
- ✅ 简单易学:代码简洁,容易理解
- ✅ 自动文档:自动生成API文档
- ✅ 性能好:运行速度快
2.2.2 创建FastAPI项目
基本结构:
1 | from fastapi import FastAPI |
2.2.3 实现CRUD接口
实际例子:实现用户管理的CRUD接口
1. 创建用户(Create):
1 | from fastapi import FastAPI, HTTPException |
2. 获取用户列表(Read - 列表):
1 | # 获取用户列表 |
3. 获取单个用户(Read - 详情):
1 | # 获取单个用户 |
4. 更新用户(Update):
1 | class UserUpdate(BaseModel): |
5. 删除用户(Delete):
1 | # 删除用户 |
2.3 接口测试
2.3.1 启动服务
1 | # 安装FastAPI |
2.3.2 使用APIFox测试
测试创建用户:
1 | 方法:POST |
测试获取用户列表:
1 | 方法:GET |
测试获取单个用户:
1 | 方法:GET |
测试更新用户:
1 | 方法:PUT |
测试删除用户:
1 | 方法:DELETE |
2.4 连接真实数据库
2.4.1 使用SQLAlchemy
SQLAlchemy = Python的数据库ORM工具,可以方便地操作数据库
安装:
1 | pip install sqlalchemy |
基本使用:
1 | from sqlalchemy import create_engine, Column, Integer, String |
2.4.2 使用数据库的CRUD接口
1 | from fastapi import Depends |
2.5 接口设计要点
2.5.1 统一响应格式
标准响应格式:
1 | { |
实际例子:
1 | # 成功响应 |
2.5.2 错误处理
常见错误:
| 错误类型 | HTTP状态码 | 说明 |
|---|---|---|
| 参数错误 | 400 | 请求参数不正确 |
| 未授权 | 401 | 未登录或Token无效 |
| 禁止访问 | 403 | 没有权限 |
| 资源不存在 | 404 | 请求的资源不存在 |
| 服务器错误 | 500 | 服务器内部错误 |
实际例子:
1 | # 用户不存在 |
2.6 实际例子:待办事项API
完整的待办事项CRUD接口:
1 | from fastapi import FastAPI, HTTPException |
💡 关键理解:
后端API的核心就是实现CRUD操作,将前端请求转换为数据库操作,并返回结果。
掌握了CRUD接口的实现,就掌握了后端开发的基础!
3. 数据验证
3.1 为什么需要数据验证?
问题:前端传来的数据一定正确吗?
实际情况:
- ❌ 用户可能输入错误的数据
- ❌ 前端可能被绕过(直接调用API)
- ❌ 恶意用户可能发送恶意数据
生活类比:
- 没有验证:任何人都能进入,不安全
- 有验证:检查身份和权限,安全可靠
实际例子:
1 | # ❌ 没有验证的接口 |
3.2 使用Pydantic进行数据验证
3.2.1 Pydantic简介
Pydantic = Python的数据验证库,FastAPI内置支持
特点:
- ✅ 自动验证数据类型
- ✅ 自动验证数据格式
- ✅ 自动生成错误信息
- ✅ 代码简洁易读
3.2.2 基本验证
定义数据模型:
1 | from pydantic import BaseModel, EmailStr |
自动验证:
1 | # ✅ 正确的数据 |
3.3 常用验证规则
3.3.1 字符串验证
长度限制:
1 | from pydantic import BaseModel, Field |
正则表达式验证:
1 | from pydantic import BaseModel, Field, validator |
3.3.2 数字验证
范围限制:
1 | from pydantic import BaseModel, Field |
3.3.3 邮箱验证
使用EmailStr:
1 | from pydantic import BaseModel, EmailStr |
3.3.4 枚举验证
限制可选值:
1 | from pydantic import BaseModel |
3.4 实际例子:用户注册验证
完整的用户注册接口:
1 | from fastapi import FastAPI, HTTPException |
测试:
1 | # ✅ 正确的数据 |
3.5 验证错误处理
3.5.1 FastAPI自动处理验证错误
当数据验证失败时,FastAPI会自动返回错误信息:
1 | { |
3.5.2 自定义错误信息
使用Field的description和自定义validator:
1 | from pydantic import BaseModel, Field, validator |
3.6 实际例子:文章发布验证
文章发布接口的完整验证:
1 | from fastapi import FastAPI |
3.7 数据验证最佳实践
验证原则:
| 原则 | 说明 | 例子 |
|---|---|---|
| 前端验证 + 后端验证 | 前端验证提升用户体验,后端验证保证安全 | 前端提示"密码太短",后端拒绝无效数据 |
| 尽早验证 | 在数据进入业务逻辑前就验证 | 在接口入口处验证,不要等到数据库操作时 |
| 清晰的错误信息 | 告诉用户哪里错了,怎么改 | "密码至少6个字符"比"验证失败"更清晰 |
| 验证所有输入 | 不要相信任何输入,都要验证 | 即使用户ID也要验证是否存在 |
实际例子:
1 | # ✅ 好的验证 |
💡 关键理解:
数据验证是后端安全的第一道防线。
永远不要相信前端传来的数据,必须在后端进行验证!
4. AI实战:使用AI实现Excel导入导出
4.1 任务描述
需求:实现一个Excel文件的导入导出功能
功能要求:
- 导入功能:上传Excel文件,解析数据并保存到数据库
- 导出功能:从数据库查询数据,生成Excel文件并下载
- 数据验证:导入时验证数据格式和内容
实际应用场景:
- 批量导入用户数据
- 导出报表数据
- 数据备份和恢复
4.2 第一步:设计Prompt
给AI的Prompt:
1 | 请帮我实现一个Excel导入导出功能,要求如下: |
4.3 AI生成的代码(示例)
4.3.1 安装依赖
1 | pip install fastapi uvicorn openpyxl python-multipart |
4.3.2 完整代码实现
1 | from fastapi import FastAPI, UploadFile, File, HTTPException |
4.3.3 代码解析
核心功能:
导入功能:
- 接收Excel文件上传
- 使用
openpyxl读取Excel - 验证表头格式
- 逐行解析数据并验证
- 保存到数据库
导出功能:
- 从数据库查询数据
- 使用
openpyxl创建Excel - 设置表头和样式
- 填充数据
- 返回文件下载
数据验证:
- 验证文件类型
- 验证表头格式
- 验证每行数据(姓名、邮箱、年龄)
- 检查重复数据
4.4 测试接口
4.4.1 测试导入功能
使用APIFox测试:
1 | 方法:POST |
Excel文件格式:
| 姓名 | 邮箱 | 年龄 |
|---|---|---|
| 张三 | zhangsan@example.com | 20 |
| 李四 | lisi@example.com | 25 |
| 王五 | wangwu@example.com | 30 |
4.4.2 测试导出功能
1 | 方法:GET |
响应:自动下载Excel文件
4.5 优化建议
4.5.1 处理大文件
问题:如果Excel文件很大(几万行),一次性加载到内存会占用很多内存
解决方案:分批处理
1 | # 分批处理,每次处理1000行 |
4.5.2 异步处理
问题:导入大文件时,接口响应时间很长
解决方案:使用后台任务
1 | from fastapi import BackgroundTasks |
4.5.3 错误处理优化
返回详细的错误信息:
1 | # 返回每行的错误详情 |
💡 关键理解:
Excel导入导出是常见的业务需求。
使用AI可以快速生成代码,但需要理解代码逻辑,并根据实际需求进行优化。
5. 选讲:数据库索引优化
5.1 为什么需要索引?
问题:数据库中有100万条用户数据,如何快速找到某个用户?
没有索引的情况:
1 | -- 查找邮箱为 "zhangsan@example.com" 的用户 |
有索引的情况:
1 | -- 创建索引后 |
生活类比:
- 没有索引:在一本没有目录的书中找内容,需要逐页翻找
- 有索引:使用目录,直接翻到对应页码
5.2 什么是索引?
索引 = 数据库的"目录",帮助快速定位数据
工作原理:
- 数据库为索引字段创建额外的数据结构(如B+树)
- 查询时,先查索引,找到数据位置
- 根据位置,直接读取数据
实际例子:
1 | 用户表(users): |
5.3 索引的类型
5.3.1 主键索引(PRIMARY KEY)
特点:
- ✅ 自动创建(定义主键时自动创建)
- ✅ 唯一性(不能有重复值)
- ✅ 非空(不能为NULL)
实际例子:
1 | CREATE TABLE users ( |
5.3.2 唯一索引(UNIQUE)
特点:
- ✅ 唯一性(不能有重复值)
- ✅ 可以为NULL(但NULL值只能有一个)
实际例子:
1 | CREATE TABLE users ( |
5.3.3 普通索引(INDEX)
特点:
- ✅ 允许重复值
- ✅ 提高查询速度
实际例子:
1 | -- 创建普通索引 |
5.3.4 组合索引(复合索引)
特点:
- ✅ 多个字段组合成一个索引
- ✅ 适合多字段查询
实际例子:
1 | -- 创建组合索引 |
5.4 什么时候需要创建索引?
5.4.1 需要创建索引的场景
| 场景 | 说明 | 例子 |
|---|---|---|
| 主键字段 | 自动创建,无需手动创建 | id INT PRIMARY KEY |
| 唯一字段 | 经常用于查询和关联 | email VARCHAR(100) UNIQUE |
| 外键字段 | 经常用于关联查询 | user_id INT, FOREIGN KEY (user_id) REFERENCES users(id) |
| 经常查询的字段 | WHERE条件中经常使用的字段 | status TINYINT, INDEX idx_status(status) |
| 经常排序的字段 | ORDER BY中经常使用的字段 | created_at DATETIME, INDEX idx_created_at(created_at) |
| 经常分组的字段 | GROUP BY中经常使用的字段 | category VARCHAR(50), INDEX idx_category(category) |
5.4.2 不需要创建索引的场景
| 场景 | 说明 |
|---|---|
| 数据量小的表 | 少于1000行的表,索引效果不明显 |
| 很少查询的字段 | 几乎不用于查询条件的字段 |
| 经常更新的字段 | 索引需要维护,更新频繁会影响性能 |
| 文本字段(过长) | TEXT、LONGTEXT等,索引效果差 |
5.5 索引的优缺点
5.5.1 优点
| 优点 | 说明 |
|---|---|
| 提高查询速度 | 查询速度提升几十倍甚至上百倍 |
| 加速排序 | ORDER BY操作更快 |
| 加速关联 | JOIN操作更快 |
| 保证唯一性 | 唯一索引保证数据唯一 |
5.5.2 缺点
| 缺点 | 说明 |
|---|---|
| 占用存储空间 | 索引需要额外的存储空间 |
| 降低写入速度 | INSERT、UPDATE、DELETE时需要更新索引 |
| 维护成本 | 索引需要定期维护 |
实际例子:
1 | -- 没有索引:插入快,查询慢 |
5.6 实际例子:博客系统索引设计
用户表(users):
1 | CREATE TABLE users ( |
文章表(articles):
1 | CREATE TABLE articles ( |
评论表(comments):
1 | CREATE TABLE comments ( |
索引使用场景:
1 | -- ✅ 使用索引的查询 |
5.7 索引优化技巧
5.7.1 最左前缀原则
组合索引遵循最左前缀原则:
1 | -- 创建组合索引 |
5.7.2 避免过多索引
问题:索引不是越多越好
原因:
- ❌ 每个索引都需要存储空间
- ❌ 每次INSERT/UPDATE/DELETE都需要更新所有相关索引
- ❌ 索引过多会影响写入性能
建议:
- ✅ 只为经常查询的字段创建索引
- ✅ 定期检查未使用的索引并删除
5.7.3 索引字段选择
选择原则:
| 字段类型 | 是否适合索引 | 说明 |
|---|---|---|
| 整数类型 | ✅ 非常适合 | INT、TINYINT等,查询效率高 |
| 短字符串 | ✅ 适合 | VARCHAR(50)以内,可以创建索引 |
| 长字符串 | ⚠️ 谨慎使用 | VARCHAR(255)以上,索引效果差 |
| 文本类型 | ❌ 不适合 | TEXT、LONGTEXT,无法创建普通索引 |
| 日期时间 | ✅ 适合 | DATETIME、TIMESTAMP,经常用于排序 |
5.8 查看索引使用情况
5.8.1 查看表的索引
1 | -- 查看表的所有索引 |
5.8.2 分析查询是否使用索引
1 | -- 使用EXPLAIN分析查询 |
5.9 索引优化总结
创建索引的原则:
- 主键和外键:必须创建索引
- 经常查询的字段:创建索引
- 经常排序的字段:创建索引
- 组合查询:创建组合索引
- 不要过度索引:只为必要的字段创建索引
索引优化检查清单:
- ✅ 主键字段有索引
- ✅ 外键字段有索引
- ✅ 唯一字段有索引
- ✅ 经常WHERE的字段有索引
- ✅ 经常ORDER BY的字段有索引
- ✅ 组合查询有组合索引
- ❌ 没有为很少查询的字段创建索引
- ❌ 没有为TEXT字段创建普通索引
💡 关键理解:
索引是数据库性能优化的关键。
合理使用索引可以大幅提升查询速度,但也要注意不要过度索引。
对于初学者,先为主键、外键、唯一字段创建索引,再根据实际查询需求添加其他索引。
本章总结
通过本章的学习,你已经掌握了:
✅ 数据库设计:
- MySQL数据类型的选择(TINYINT、VARCHAR、TEXT等)
- 根据实际需求选择合适的数据类型
- 节省存储空间,提高查询性能
✅ API实现:
- 使用FastAPI实现CRUD接口
- 连接数据库进行数据操作
- 统一响应格式和错误处理
✅ 数据验证:
- 使用Pydantic进行数据验证
- 常用验证规则(字符串、数字、邮箱等)
- 验证错误处理
✅ 实战技能:
- 使用AI实现Excel导入导出功能
- 处理文件上传和下载
- 数据验证和错误处理
✅ 进阶知识(选讲):
- 数据库索引的作用和类型
- 索引的创建和使用
- 索引优化技巧
🌟 恭喜你!
你已经掌握了后端开发的基础技能!
这些知识将帮助你:
设计合理的数据库结构
实现规范的API接口
处理数据验证和错误
优化数据库查询性能
记住:后端开发的核心是数据处理和业务逻辑!
继续练习,继续探索,后端开发的世界等着你! 🚀