MySQL 从入门到实战

MySQL 从入门到实战

一、数据库基础:先搞懂核心概念

1. 什么是数据库?

数据库(Database)是长期存储在计算机中的结构化数据集合,可以理解为"电子化的文件柜"------用于存储、管理和查询数据,且数据之间存在关联关系。

2. 关系型数据库 vs 非关系型数据库

  • 关系型数据库(如 MySQL、Oracle):数据以"表"的形式存储,表与表之间通过"主键""外键"关联,数据结构固定,支持复杂查询(如多表关联、统计分析);
  • 非关系型数据库(如 Redis、MongoDB):数据以"键值对""文档"等形式存储,结构灵活,适合高并发、大数据量场景。

3. MySQL 核心术语

术语 通俗解释 示例
数据库(DB) 存储数据的"仓库",一个数据库包含多个表 student_db(学生信息数据库)
表(Table) 数据库中存储数据的核心单元,由行和列组成 student(学生表)
列(Column) 表中的"字段",存储同一类数据 name(姓名列)、age(年龄列)
行(Row) 表中的"记录",对应一条完整的数据 1001张三20
主键(PK) 表中唯一标识一条记录的列(不可重复、非空) id(学生编号,唯一标识学生)
外键(FK) 表中关联其他表主键的列(建立表之间的关系) class_id(关联班级表的主键)
SQL 操作数据库的语言(结构化查询语言) SELECT * FROM student

二、MySQL 安装与环境配置(Windows/Mac 通用)

1. 下载 MySQL

  • 官网地址:https://dev.mysql.com/downloads/mysql/
  • 版本选择:推荐 8.0 版本(稳定且功能完善),根据操作系统选择对应安装包(Windows 选 MSI,Mac 选 DMG)。

2. 安装关键步骤

Windows 系统
  1. 运行安装包,选择"Custom"自定义安装,勾选"MySQL Server";
  2. 配置端口(默认 3306,无需修改);
  3. 设置 root 账号密码(务必牢记,后续登录用);
  4. 安装完成后,通过"MySQL 8.0 Command Line Client"启动命令行工具,输入密码登录。
Mac 系统
  1. 运行 DMG 安装包,按提示完成安装;
  2. 打开"系统偏好设置"→"MySQL",启动 MySQL 服务;
  3. 打开终端,输入命令登录:mysql -u root -p,然后输入安装时设置的密码。

3. 验证安装成功

登录后输入以下命令,若返回 MySQL 版本信息,则安装成功:

sql 复制代码
SELECT VERSION();

三、MySQL 核心语法:CRUD 操作全解析

CRUD 是数据库操作的核心(Create 新增、Read 查询、Update 修改、Delete 删除),以下所有示例基于「学生表(student)」和「班级表(class)」展开。

1. 数据库操作(创建/查看/删除)

(1)创建数据库
sql 复制代码
-- 创建数据库(指定字符集为 UTF-8,避免中文乱码)
CREATE DATABASE IF NOT EXISTS student_db 
CHARACTER SET utf8mb4 
COLLATE utf8mb4_general_ci;

-- 切换到该数据库(后续操作默认在该数据库下执行)
USE student_db;
(2)查看/删除数据库
sql 复制代码
-- 查看所有数据库
SHOW DATABASES;

-- 查看当前使用的数据库
SELECT DATABASE();

-- 删除数据库(谨慎使用!会删除所有表和数据)
DROP DATABASE IF EXISTS student_db;

2. 表操作(创建/查看/修改/删除)

(1)创建表

先创建「班级表(class)」,再创建「学生表(student)」(通过外键关联班级表):

sql 复制代码
-- 创建班级表(主键为 class_id)
CREATE TABLE IF NOT EXISTS class (
    class_id INT PRIMARY KEY AUTO_INCREMENT, -- 自增主键(自动生成唯一ID)
    class_name VARCHAR(50) NOT NULL, -- 班级名称(非空)
    grade INT NOT NULL -- 年级(非空)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

-- 创建学生表(外键关联班级表的 class_id)
CREATE TABLE IF NOT EXISTS student (
    id INT PRIMARY KEY AUTO_INCREMENT, -- 学生编号(自增主键)
    name VARCHAR(50) NOT NULL, -- 姓名(非空)
    age INT CHECK (age > 0 AND age < 100), -- 年龄(范围校验:1-99)
    gender ENUM('男', '女', '其他') DEFAULT '男', -- 性别(枚举类型,默认男)
    class_id INT, -- 关联班级表的主键
    create_time DATETIME DEFAULT CURRENT_TIMESTAMP, -- 创建时间(默认当前时间)
    -- 外键约束:student.class_id 关联 class.class_id
    FOREIGN KEY (class_id) REFERENCES class(class_id)
    ON DELETE SET NULL -- 若班级表的记录被删除,学生表的 class_id 设为 NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
(2)查看表结构
sql 复制代码
-- 查看数据库中所有表
SHOW TABLES;

-- 查看表的字段信息(详细)
DESCRIBE student; -- 或简写 DESC student;

-- 查看表的创建语句
SHOW CREATE TABLE student;
(3)修改表结构(ALTER TABLE)
sql 复制代码
-- 1. 给学生表添加"手机号"字段
ALTER TABLE student ADD COLUMN phone VARCHAR(20) UNIQUE; -- UNIQUE:手机号唯一

-- 2. 修改"年龄"字段的默认值为 18
ALTER TABLE student ALTER COLUMN age SET DEFAULT 18;

-- 3. 删除"手机号"字段
ALTER TABLE student DROP COLUMN phone;

-- 4. 重命名表(将 student 改为 student_info)
ALTER TABLE student RENAME TO student_info;
(4)删除表
sql 复制代码
-- 删除表(若存在)
DROP TABLE IF EXISTS student_info;

3. 数据操作(CRUD 核心)

(1)新增数据(INSERT)
sql 复制代码
-- 1. 给班级表插入数据(指定字段)
INSERT INTO class (class_name, grade) 
VALUES ('一年级1班', 1), ('一年级2班', 1), ('二年级1班', 2);

-- 2. 给学生表插入数据(省略字段,按表结构顺序插入)
INSERT INTO student (name, age, gender, class_id)
VALUES 
('张三', 20, '男', 1),
('李四', 19, '女', 1),
('王五', 21, '男', 2),
('赵六', 18, '女', 3);

-- 3. 插入部分字段(未指定的字段用默认值)
INSERT INTO student (name, class_id)
VALUES ('孙七', 2); -- age 默认为 18,gender 默认为男
(2)查询数据(SELECT,最常用!)
基础查询
sql 复制代码
-- 1. 查询学生表所有字段的所有记录(* 表示所有字段,不推荐生产环境使用)
SELECT * FROM student;

-- 2. 查询指定字段(姓名、年龄、班级ID)
SELECT name, age, class_id FROM student;

-- 3. 给字段起别名(简化输出)
SELECT name AS 姓名, age AS 年龄 FROM student;

-- 4. 去重查询(查询所有班级ID,去除重复值)
SELECT DISTINCT class_id FROM student;
条件查询(WHERE)
sql 复制代码
-- 1. 查询年龄大于 19 的学生
SELECT * FROM student WHERE age > 19;

-- 2. 查询性别为女且班级ID为 1 的学生
SELECT * FROM student WHERE gender = '女' AND class_id = 1;

-- 3. 查询班级ID为 1 或 3 的学生
SELECT * FROM student WHERE class_id IN (1, 3);

-- 4. 查询姓名包含"张"字的学生(模糊查询,% 表示任意字符)
SELECT * FROM student WHERE name LIKE '%张%';

-- 5. 查询年龄为空的学生(IS NULL 判空)
SELECT * FROM student WHERE age IS NULL;
排序查询(ORDER BY)
sql 复制代码
-- 1. 按年龄升序排序(ASC 可省略,默认升序)
SELECT * FROM student ORDER BY age ASC;

-- 2. 按班级ID降序,年龄升序排序(多字段排序)
SELECT * FROM student ORDER BY class_id DESC, age ASC;
分页查询(LIMIT,避免数据过多)
sql 复制代码
-- 分页查询:从第 0 条记录开始,查询 2 条(适用于第一页)
SELECT * FROM student LIMIT 0, 2;

-- 简化写法(从第 0 条开始可省略第一个参数)
SELECT * FROM student LIMIT 2;

-- 查询第 2 页数据(每页 2 条:第 3-4 条记录)
SELECT * FROM student LIMIT 2, 2;
聚合查询(COUNT/SUM/AVG/MAX/MIN)
sql 复制代码
-- 1. 统计学生总数
SELECT COUNT(*) AS 学生总数 FROM student;

-- 2. 统计每个班级的学生人数(GROUP BY 分组)
SELECT class_id AS 班级ID, COUNT(*) AS 学生人数 
FROM student 
GROUP BY class_id;

-- 3. 计算学生的平均年龄
SELECT AVG(age) AS 平均年龄 FROM student;

-- 4. 查询最大年龄和最小年龄
SELECT MAX(age) AS 最大年龄, MIN(age) AS 最小年龄 FROM student;
多表关联查询(JOIN)

需求:查询学生的姓名、年龄、班级名称(关联 student 表和 class 表)

sql 复制代码
-- INNER JOIN:只查询两张表中匹配的记录(学生有班级,班级有学生)
SELECT s.name AS 姓名, s.age AS 年龄, c.class_name AS 班级名称
FROM student s -- 给表起别名 s(简化写法)
INNER JOIN class c -- 给表起别名 c
ON s.class_id = c.class_id; -- 关联条件:学生表的 class_id = 班级表的 class_id

-- LEFT JOIN:查询学生表所有记录,即使没有班级(class_name 为 NULL)
SELECT s.name, c.class_name 
FROM student s
LEFT JOIN class c
ON s.class_id = c.class_id;
(3)修改数据(UPDATE,谨慎使用!)
sql 复制代码
-- 修改姓名为"张三"的学生年龄为 22(必须加 WHERE 条件,否则修改所有记录)
UPDATE student 
SET age = 22 
WHERE name = '张三';

-- 同时修改多个字段(修改李四的性别和班级ID)
UPDATE student 
SET gender = '男', class_id = 2 
WHERE name = '李四';
(4)删除数据(DELETE,谨慎使用!)
sql 复制代码
-- 删除姓名为"孙七"的学生(必须加 WHERE 条件,否则删除所有记录)
DELETE FROM student 
WHERE name = '孙七';

-- 删除班级ID为 3 的所有学生
DELETE FROM student 
WHERE class_id = 3;

4. 约束条件(保证数据完整性)

约束是表设计的核心,用于限制字段的值,避免无效数据插入:

sql 复制代码
-- 常见约束示例(创建表时添加)
CREATE TABLE IF NOT EXISTS user (
    id INT PRIMARY KEY AUTO_INCREMENT, -- 主键约束(唯一、非空)
    username VARCHAR(50) NOT NULL UNIQUE, -- 非空约束 + 唯一约束(用户名不能重复)
    password VARCHAR(100) NOT NULL, -- 非空约束(密码必填)
    email VARCHAR(100) CHECK (email LIKE '%@%'), -- 检查约束(邮箱格式)
    status TINYINT DEFAULT 1 -- 默认约束(状态默认1:正常)
);

四、MySQL 实战案例:学生成绩管理系统

需求描述

设计一个简单的学生成绩管理系统,包含 3 张表:

  1. class(班级表):存储班级信息;
  2. student(学生表):存储学生基本信息,关联班级表;
  3. score(成绩表):存储学生的科目成绩,关联学生表。

1. 创建表结构

sql 复制代码
-- 1. 班级表
CREATE TABLE IF NOT EXISTS class (
    class_id INT PRIMARY KEY AUTO_INCREMENT,
    class_name VARCHAR(50) NOT NULL,
    grade INT NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

-- 2. 学生表
CREATE TABLE IF NOT EXISTS student (
    id INT PRIMARY KEY AUTO_INCREMENT,
    name VARCHAR(50) NOT NULL,
    age INT DEFAULT 18,
    gender ENUM('男', '女', '其他') DEFAULT '男',
    class_id INT,
    FOREIGN KEY (class_id) REFERENCES class(class_id) ON DELETE SET NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

-- 3. 成绩表
CREATE TABLE IF NOT EXISTS score (
    score_id INT PRIMARY KEY AUTO_INCREMENT,
    student_id INT NOT NULL,
    subject VARCHAR(50) NOT NULL, -- 科目
    score INT CHECK (score BETWEEN 0 AND 100), -- 成绩(0-100分)
    exam_time DATE NOT NULL, -- 考试时间
    FOREIGN KEY (student_id) REFERENCES student(id) ON DELETE CASCADE -- 学生删除,成绩也删除
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

2. 插入测试数据

sql 复制代码
-- 插入班级数据
INSERT INTO class (class_name, grade) VALUES ('一年级1班', 1), ('一年级2班', 1);

-- 插入学生数据
INSERT INTO student (name, age, gender, class_id) 
VALUES ('张三', 20, '男', 1), ('李四', 19, '女', 1), ('王五', 21, '男', 2);

-- 插入成绩数据
INSERT INTO score (student_id, subject, score, exam_time)
VALUES 
(1, '语文', 85, '2024-06-10'),
(1, '数学', 92, '2024-06-10'),
(2, '语文', 78, '2024-06-10'),
(2, '数学', 88, '2024-06-10'),
(3, '语文', 95, '2024-06-10'),
(3, '数学', 80, '2024-06-10');

3. 核心查询场景

(1)查询每个学生的所有科目成绩(关联 3 张表)
sql 复制代码
SELECT 
    s.name AS 姓名,
    c.class_name AS 班级,
    sc.subject AS 科目,
    sc.score AS 成绩,
    sc.exam_time AS 考试时间
FROM student s
INNER JOIN class c ON s.class_id = c.class_id
INNER JOIN score sc ON s.id = sc.student_id
ORDER BY s.name, sc.subject;
(2)查询每个学生的总分和平均分
sql 复制代码
SELECT 
    s.name AS 姓名,
    COUNT(sc.subject) AS 考试科目数,
    SUM(sc.score) AS 总分,
    ROUND(AVG(sc.score), 2) AS 平均分 -- ROUND 保留 2 位小数
FROM student s
LEFT JOIN score sc ON s.id = sc.student_id
GROUP BY s.id, s.name
ORDER BY 总分 DESC;
(3)查询数学成绩大于 85 分的学生信息
sql 复制代码
SELECT 
    s.name AS 姓名,
    c.class_name AS 班级,
    sc.score AS 数学成绩
FROM student s
INNER JOIN class c ON s.class_id = c.class_id
INNER JOIN score sc ON s.id = sc.student_id
WHERE sc.subject = '数学' AND sc.score > 85;
(4)查询每个班级的语文平均分(按班级分组)
sql 复制代码
SELECT 
    c.class_name AS 班级,
    ROUND(AVG(sc.score), 2) AS 语文平均分
FROM class c
LEFT JOIN student s ON c.class_id = s.class_id
LEFT JOIN score sc ON s.id = sc.student_id AND sc.subject = '语文'
GROUP BY c.class_id, c.class_name;

五、MySQL 优化技巧:让查询更快、更稳定

1. 索引优化(核心!)

索引是提高查询速度的关键,相当于书的"目录",能快速定位数据:

(1)创建索引
sql 复制代码
-- 给学生表的 name 字段创建普通索引(查询姓名时加速)
CREATE INDEX idx_student_name ON student(name);

-- 给成绩表的 student_id + subject 创建联合索引(多字段查询加速)
CREATE INDEX idx_score_student_subject ON score(student_id, subject);

-- 给经常用于排序的字段创建索引(ORDER BY 加速)
CREATE INDEX idx_student_age ON student(age);
(2)索引使用原则
  • 索引不是越多越好:过多索引会减慢插入/修改/删除速度(索引需要维护);
  • 适合创建索引的字段:经常用于查询(WHERE)、排序(ORDER BY)、关联(JOIN)的字段;
  • 不适合创建索引的字段:数据重复率高(如 gender,只有男/女/其他)、字段长度过长(如 VARCHAR(2000))。

2. SQL 语句优化

(1)避免使用 SELECT *

只查询需要的字段,减少数据传输和内存消耗:

sql 复制代码
-- 坏示例:查询所有字段
SELECT * FROM student;

-- 好示例:只查询需要的字段
SELECT name, age, class_id FROM student;
(2)避免 WHERE 子句中使用函数或运算

会导致索引失效,查询变慢:

sql 复制代码
-- 坏示例:对 age 字段做运算,索引失效
SELECT * FROM student WHERE age + 1 = 20;

-- 好示例:改写为字段直接比较
SELECT * FROM student WHERE age = 19;
(3)使用 LIMIT 限制返回数据量

避免一次性查询大量数据,导致内存溢出:

sql 复制代码
-- 好示例:分页查询前 10 条数据
SELECT * FROM student LIMIT 10;

3. 数据库设计优化

  • 表的字段类型尽量小:如年龄用 INT(4字节),不用 BIGINT(8字节);
  • 避免使用 NULL 值:NULL 值会增加查询复杂度,可用默认值替代(如 age 默认为 0);
  • 分表分库:大数据量场景(如千万级数据),可按时间、地区等维度分表(如 score_202406、score_202407)。

六、MySQL 常见问题与避坑指南

1. 中文乱码问题

  • 原因:数据库/表/字段的字符集不是 UTF-8;
  • 解决方案:创建数据库时指定字符集为 utf8mb4(支持所有中文和表情符号),如下:
sql 复制代码
CREATE DATABASE student_db CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;

2. 主键自增重复问题

  • 原因:手动插入了自增主键的值,导致后续自增ID冲突;
  • 解决方案:避免手动插入自增主键,让 MySQL 自动生成;若必须插入,插入后执行 ALTER TABLE student AUTO_INCREMENT = (SELECT MAX(id) + 1 FROM student); 重置自增ID。

3. 外键约束导致数据无法删除

  • 原因:子表(如 student)关联了父表(如 class)的主键,直接删除父表记录会触发外键约束;
  • 解决方案:创建外键时指定 ON DELETE CASCADE(父表记录删除,子表关联记录也删除)或 ON DELETE SET NULL(父表记录删除,子表外键设为 NULL)。

4. 索引失效的常见场景

  • WHERE 子句中使用 !=<>IS NOT NULL
  • 使用 LIKE '%xxx'(前缀模糊查询,后缀模糊查询 xxx% 不会失效);
  • 字段类型不匹配(如字符串字段用数字查询:WHERE name = 123);
  • 联合索引不满足"最左前缀原则"(如联合索引 (a,b,c),查询条件只有 b 和 c,索引失效)。

七、总结:MySQL 学习路径建议

  1. 基础阶段:掌握数据库/表的创建、CRUD 基础操作,能独立完成简单查询;
  2. 进阶阶段:深入学习多表关联查询、聚合查询、索引优化,理解约束和事务;
  3. 实战阶段:结合项目开发(如 Spring Boot + MySQL),解决实际业务场景中的数据存储和查询问题;
  4. 优化阶段:学习性能调优、分表分库、主从复制等高级特性,应对大数据量、高并发场景。
相关推荐
小陈工3 小时前
Python Web开发入门(十七):Vue.js与Python后端集成——让前后端真正“握手言和“
开发语言·前端·javascript·数据库·vue.js·人工智能·python
0xDevNull7 小时前
MySQL数据冷热分离详解
后端·mysql
科技小花8 小时前
数据治理平台架构演进观察:AI原生设计如何重构企业数据管理范式
数据库·重构·架构·数据治理·ai-native·ai原生
一江寒逸8 小时前
零基础从入门到精通MySQL(中篇):进阶篇——吃透多表查询、事务核心与高级特性,搞定复杂业务SQL
数据库·sql·mysql
D4c-lovetrain8 小时前
linux个人心得22 (mysql)
数据库·mysql
阿里小阿希8 小时前
CentOS7 PostgreSQL 9.2 升级到 15 完整教程
数据库·postgresql
荒川之神8 小时前
Oracle 数据仓库雪花模型设计(完整实战方案)
数据库·数据仓库·oracle
做个文艺程序员9 小时前
MySQL安全加固十大硬核操作
数据库·mysql·安全
不吃香菜学java9 小时前
Redis简单应用
数据库·spring boot·tomcat·maven
一个天蝎座 白勺 程序猿9 小时前
Apache IoTDB(15):IoTDB查询写回(INTO子句)深度解析——从语法到实战的ETL全链路指南
数据库·apache·etl·iotdb