第5章 5.1 MySQL 基础与数据库入门(Python 版)

🎯 开场:为什么你的程序需要"仓库"?

想象一下:你开了一家奶茶店,每天卖多少杯、谁买的、几点买的……全记在脑子里。第一天 10 个顾客你能记住,第三天 100 个订单你就蒙了。

程序也一样——用户注册的信息、订单数据、配置参数……全存在变量里?程序一关全没了。

这就是数据库存在的意义:给程序找一个永久存放数据的地方

你上一章(4.5 登录注册系统)把用户数据存在数组里,刷新页面就丢了,对吧?这一章我们来解决这个问题——学会用 MySQL 这个"超级 Excel",让你的程序记住用户的数据

学完本文,你将能:
- 说出 MySQL 和 SQL 是什么关系
- 用 Python 连上 MySQL 数据库
- 完成"增删改查"基本操作
- 用可视化工具 phpMyAdmin 看懂你的数据


🧱 基础:3 个核心概念(25 分钟)

什么是数据库?—— 比喻篇

数据库(Database) = 一个仓库,里面有很多\n\nSimple tech illustration expla\n\nAI comic creation scene, creat\n\n柜子(表)

生活例子 技术对应
一栋大楼 MySQL 服务器
大楼的某一层 一个 Database
这一层的柜子 Database 里的 Table(表)
柜子里的文件 Table 里的数据行(Record)

SQL(Structured Query Language) = 仓库管理员的"指令手册",用来告诉数据库你要做什么。

为什么要用 MySQL?

  • 免费开源:不花钱,足够强大
  • 速度快:处理百万级数据毫无压力
  • 全世界的网站:Facebook、Twitter、YouTube 都在用
  • 配套工具多:phpMyAdmin 就是其中之一,一个网页版的"数据库控制台"

怎么用?先安装!(Mac 用户看这里)

方法一:Homebrew(一键安装)

brew install mysql
brew install --cask phpmyadmin

方法二:MAMP(推荐新手)
下载 MAMP(免费版),安装后自带 MySQL + phpMyAdmin,点一下"Start"就启动了。

说白了:MySQL 是"仓库",phpMyAdmin 是"仓库管理界面",让你不用记命令也能操作仓库。

🎉 第一个 MySQL 命令(5 分钟上手)

打开终端,连上 MySQL:

mysql -u root -p

输入密码后,你会看到这样的提示符:

mysql>

创建一个"奶茶店数据库":

CREATE DATABASE milktea_shop;
USE milktea_shop;

创建一个"订单表":

CREATE TABLE orders (
id INT AUTO_INCREMENT PRIMARY KEY,
customer_name VARCHAR(50),
drink VARCHAR(50),
price DECIMAL(10,2),
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

插入一条数据:

INSERT INTO orders (customer_name, drink, price) VALUES ('小明', '珍珠奶茶', 18.5);

查看数据:

SELECT * FROM orders;

预期输出:

+----+---------------+-----------+-------+---------------------+
| id | customer_name | drink     | price | created_at          |
+----+---------------+-----------+-------+---------------------+
|  1 | 小明          | 珍珠奶茶  | 18.50 | 2024-01-15 10:30:00 |
+----+---------------+-----------+-------+---------------------+

一句话解释:这就是 SQL——用类似英语的语句,告诉数据库"我要查/增/改/删"数据。

Python 怎么连 MySQL?

终于到 Python 了!用 mysql-connector-python 这个库:

安装:

pip install mysql-connector-python

连接数据库(3 行搞定):

import mysql.connector

conn = mysql.connector.connect(
host="localhost",
user="root",
password="你的密码",
database="milktea_shop"
)
cursor = conn.cursor()

print("连接成功!")

查询数据:

cursor.execute("SELECT * FROM orders")
results = cursor.fetchall()

for row in results:
print(f"顾客:{row[1]},饮品:{row[2]},价格:{row[3]}元")

预期输出:

顾客:小明,饮品:珍珠奶茶,价格:18.5元

插入数据(带参数防注入):

sql = "INSERT INTO orders (customer_name, drink, price) VALUES (%s, %s, %s)"
values = ("小红", "椰果奶茶", 20.0)

cursor.execute(sql, values)
conn.commit()  # 重要!不提交就不会存进去

print(f"插入成功,ID:{cursor.lastrowid}")

注意!:Python 字符串拼 SQL 很危险(会被黑客攻击),后面 5.2 章我们会详细讲预处理语句。

CRUD 完整操作一览

import mysql.connector

conn = mysql.connector.connect(
host="localhost",
user="root",
password="你的密码",
database="milktea_shop"
)
cursor = conn.cursor()

# ===== Create(增) =====
cursor.execute("INSERT INTO orders (customer_name, drink, price) VALUES ('小刚', '柠檬茶', 15.0)")
conn.commit()

# ===== Read(查) =====
cursor.execute("SELECT * FROM orders WHERE price > 15")
for row in cursor.fetchall():
print(row)

# ===== Update(改) =====
cursor.execute("UPDATE orders SET price = 22.0 WHERE customer_name = '小刚'")
conn.commit()

# ===== Delete(删) =====
cursor.execute("DELETE FROM orders WHERE customer_name = '小刚'")
conn.commit()

conn.close()

一句记住 CRUD:「查」单词是 SELECT,「增」是 INSERT,「改」是 UPDATE,「删」是 DELETE——都是英语,不用背,看多了就认识。


🔥 实战:3 个递进小项目(35 分钟)

项目 1:Python 读取数据库(5 分钟)

目标:把 phpMyAdmin 里的数据显示在 Python 控制台。

完整代码:

import mysql.connector

# 连接数据库
conn = mysql.connector.connect(
host="localhost",
user="root",
password="你的密码",
database="milktea_shop"
)
cursor = conn.cursor()

# 查询所有订单
cursor.execute("SELECT * FROM orders")
orders = cursor.fetchall()

print("=" * 40)
print("    奶茶店订单报表")
print("=" * 40)

total = 0
for order in orders:
order_id, name, drink, price, time = order
print(f"订单{order_id} | {name} | {drink} | {price}元")
total += price

print("-" * 40)
print(f"今日营收:{total} 元")
print("=" * 40)

conn.close()

预期输出:

========================================
奶茶店订单报表
========================================
订单1 | 小明 | 珍珠奶茶 | 18.5元
订单2 | 小红 | 椰果奶茶 | 20.0元
----------------------------------------
今日营收:38.5 元
========================================

一句话解释:用 fetchall() 一次取出所有行,遍历打印。


项目 2:CSV 数据批量导入(15 分钟)

背景:你的奶茶店搞活动,从大众点评导出了一份 CSV 格式的顾客反馈,要存到数据库里。

feedback.csv 内容:

customer_name,drink,price,rating
小王,芝芝芒芒,32.0,5
小李,芋泥波波,28.0,4
小张,杨枝甘露,30.0,5
小赵,奥利奥奶茶,25.0,3
小周,茉莉奶绿,22.0,4

Python 批量导入脚本:

import mysql.connector
import csv

conn = mysql.connector.connect(
host="localhost",
user="root",
password="你的密码",
database="milktea_shop"
)
cursor = conn.cursor()

# 创建新表存储评分
cursor.execute("""
CREATE TABLE IF NOT EXISTS feedback (
    id INT AUTO_INCREMENT PRIMARY KEY,
    customer_name VARCHAR(50),
    drink VARCHAR(50),
    price DECIMAL(10,2),
    rating INT
)
""")

# 读取 CSV 并插入数据库
with open('feedback.csv', 'r', encoding='utf-8') as f:
reader = csv.DictReader(f)  # 把 CSV 读成字典列表
for row in reader:
    sql = "INSERT INTO feedback (customer_name, drink, price, rating) VALUES (%s, %s, %s, %s)"
    values = (row['customer_name'], row['drink'], float(row['price']), int(row['rating']))
    cursor.execute(sql, values)

conn.commit()

# 验证:查询评分大于等于4的订单
print("评分 4 星以上的订单:")
cursor.execute("SELECT * FROM feedback WHERE rating >= 4")
for row in cursor.fetchall():
print(f"  {row[1]}点了{row[2]},给了{row[4]}星好评!")

conn.close()
print("\n导入完成!")

预期输出:

评分 4 星以上的订单:
小王点了芝芝芒芒,给了5星好评!
小李点了芋泥波波,给了4星好评!
小张点了杨枝甘露,给了5星好评!
小周点了茉莉奶绿,给了4星好评!

导入完成!

一句话解释csv.DictReader 帮你把 CSV 每行转成字典,%s 占位符防止 SQL 注入。


项目 3:简易销售统计工具(15 分钟)

目标:做一个命令行工具,统计本周卖得最好的饮品。

import mysql.connector
from collections import Counter

conn = mysql.connector.connect(
host="localhost",
user="root",
password="你的密码",
database="milktea_shop"
)
cursor = conn.cursor()

def show_stats():
print("\n" + "=" * 40)
print("  🧋 奶茶店销售统计")
print("=" * 40)

# 1. 总订单数
cursor.execute("SELECT COUNT(*) FROM orders")
total_orders = cursor.fetchone()[0]
print(f"📦 总订单数:{total_orders}")

# 2. 总营收
cursor.execute("SELECT SUM(price) FROM orders")
total_revenue = cursor.fetchone()[0] or 0
print(f"💰 总营收:{total_revenue} 元")

# 3. 最热门的饮品
cursor.execute("SELECT drink FROM orders")
drinks = [row[0] for row in cursor.fetchall()]
if drinks:
    counter = Counter(drinks)
    top_drink, count = counter.most_common(1)[0]
    print(f" 🔥 最受欢迎:{top_drink}({count} 单)")

# 4. 列出所有订单
print("\n📋 最近订单:")
cursor.execute("SELECT * FROM orders ORDER BY created_at DESC LIMIT 5")
for row in cursor.fetchall():
    print(f"   {row[4].strftime('%m-%d %H:%M')} | {row[1]} | {row[2]} | {row[3]}元")

print("=" * 40)

# 插入今天的订单演示
demo_orders = [
("小孙", "生椰拿铁", 28.0),
("小吴", "珍珠奶茶", 18.5),
("小郑", "生椰拿铁", 28.0),
]
for name, drink, price in demo_orders:
cursor.execute("INSERT INTO orders (customer_name, drink, price) VALUES (%s, %s, %s)", 
                (name, drink, price))
conn.commit()

show_stats()

conn.close()

预期输出:

========================================
🧋 奶茶店销售统计
========================================
📦 总订单数:5
💰 总营收:121.5 元
🔥 最受欢迎:生椰拿铁(2 单)

📋 最近订单:
1-15 14:30 | 小郑 | 生椰拿铁 | 28.0元
1-15 14:29 | 小吴 | 珍珠奶茶 | 18.5元
1-15 14:28 | 小孙 | 生椰拿铁 | 28.0元
========================================

一句话解释Counter 来自 collections 模块,帮你数出场次最高的元素。


💪 进阶:4 个坑 + 1 个技巧(20 分钟)

坑 1:忘记 commit()

# ❌ 错误:数据没存进去
cursor.execute("INSERT INTO orders (customer_name, drink, price) VALUES ('测试', '绿茶', 15)")
# 没有 commit()

# ✅ 正确:养成习惯,insert/update/delete 后立刻 commit
cursor.execute("INSERT INTO orders (customer_name, drink, price) VALUES ('测试', '绿茶', 15)")
conn.commit()

坑 2:中文字符乱码

# ❌ 错误:不指定字符集,遇到中文就变成 ???
conn = mysql.connector.connect(
host="localhost",
user="root",
password="密码"
)

# ✅ 正确:加上 charset='utf8mb4'(支持所有 Unicode 字符)
conn = mysql.connector.connect(
host="localhost",
user="root",
password="密码",
charset='utf8mb4'
)

坑 3:SQL 字符串拼接(会中毒!)

# ❌ 错误:用户输入 "'; DROP TABLE orders; --" 你的数据库就没了!
user_input = "' OR 1=1 --"
cursor.execute(f"SELECT * FROM users WHERE name = '{user_input}'")

# ✅ 正确:用参数化查询(下一章 5.2 会深入讲)
sql = "SELECT * FROM users WHERE name = %s"
cursor.execute(sql, (user_input,))

坑 4:关闭连接顺序

# ❌ 错误:先关 cursor 再关 conn,可能丢失未提交的数据
cursor.close()
conn.close()  # 如果刚才有插入没 commit,数据就没了

# ✅ 正确:先 commit,再关 cursor,最后关 conn
conn.commit()
cursor.close()
conn.close()

坑 5:查不到数据不报错

# ❌ 错误:以为查不到数据会返回 None 或空列表
cursor.execute("SELECT * FROM orders WHERE id = 9999")
result = cursor.fetchone()
print(result)  # 返回 None,不会报错,但如果你不检查就直接用 result[0],会崩溃

# ✅ 正确:养成检查习惯
result = cursor.fetchone()
if result:
print(result)
else:
print("没有找到这个订单")

调试技巧:用 %s 打印变量

# 复杂查询前,先打印出来看看对不对
sql = "SELECT * FROM orders WHERE customer_name = %s AND price > %s"
values = ("小明", 20)

# 打印最终的 SQL 语句(调试用)
print(f"执行SQL: {sql},参数: {values}")

cursor.execute(sql, values)

调试一句话:先打印,再执行,发现问题早处理。


✏️ 练习题 + 作业题(共 7 分钟)

练习题(5 道,10 分钟)

练习 1(1 分钟):改名字
- 输入:在项目 1 代码里,把 customer_name 改成 username
- 预期输出:正常打印(字段名变了,输出文字相应变化)
- 提示:SELECT * 会选所有列,但打印时要改成对应的列索引

练习 2(2 分钟):加个判断
- 输入:在项目 1 的循环里,加一个 if 判断,只打印价格 > 20 的订单
- 预期输出:只打印贵的订单
- 提示:if order[3] > 20:(price 是第 4 列,索引是 3)

练习 3(2 分钟):新 CSV
- 输入:创建一个 students.csv,包含 name,score 两列,3 行数据,用项目 2 的方法导入
- 预期输出:打印所有导入的数据
- 提示:表结构改成 id INT, name VARCHAR(50), score INT

练习 4(3 分钟):串项目 2+3
- 输入:用项目 2 的方法从 CSV 导入数据到 feedback 表,然后用项目 3 的 Counter 统计哪种饮品最受欢迎
- 预期输出:打印最受欢迎的饮品名称
- 提示:导入数据和统计分开做,先插入再查询

练习 5(2 分钟):找错
- 输入:以下代码运行报错 IndexError: tuple index out of range,找原因

cursor.execute("SELECT drink FROM orders")
result = cursor.fetchone()
print(result[1])  # 报错行
  • 预期输出:说明哪里错了,怎么改
  • 提示:fetchone() 返回 1 行,不是多行

作业题(30 分钟 - 2 小时)

作业:做一个「个人收支记录工具」

  • 需求:用 MySQL 存你的日常花销,Python 做个命令行界面查看统计
  • 功能点
    1. 用 SQL 创建 expenses 表(字段:id, category, amount, note, date)
    2. 用 Python 插入至少 5 条模拟收支数据
    3. 查询本周支出总额
    4. 按分类统计支出(餐饮/交通/购物/其他)
  • 加分项
    1. 支持按月份筛选查询
    2. 用 phpMyAdmin 截图展示你的数据
  • 验收标准:能跑起来 + 输出收支统计 + 代码有注释
  • 提交方式:评论区贴代码或 GitHub 链接

📚 总结 + 资源(5 分钟)

一句话记住 3 个核心点

  1. MySQL 是仓库,SQL 是指令书——用 SELECT/INSERT/UPDATE/DELETE 告诉数据库干什么
  2. Python 通过 mysql-connector-python 操控数据库——连接 → 执行 → 提交 → 关闭
  3. 参数化查询防 SQL 注入——永远别用字符串拼接 SQL(下一章会深入讲)

延伸学习资源

  1. 官方文档MySQL 8.0 Reference Manual(英文,但例子清晰)
  2. 视频教程:B 站「MySQL 入门」系列(选播放量最高的,1.5 倍速看)
  3. 工具推荐:DBeaver(免费的数据库客户端,比命令行好看)

互动钩子

你在工作/学习中用过数据库吗? 是记录用户、存订单、还是做数据分析?评论区聊聊你的使用场景,帮你想想怎么用今天学的知识解决实际问题!老粉优先回复 ~


下章预告:上一章我们学了登录注册,但密码明文存储太危险了……下一章「5.2 PDO 预处理与防 SQL 注入」会教你:怎么让黑客无法攻击你的数据库,以及预处理语句到底是什么「盾牌」?敬请期待!

声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。