MySQL 从入门到删库跑路,保姆级教程!

你是小阿巴,刚入行的程序员。

这天,你接到一个私活:帮学校做个学生管理系统,要能管理学生信息、记录成绩、统计数据。

你一听,这不简单吗?用 Java 写个程序,把数据存到 Map 里就搞定了。

复制代码
public class StudentManagementSystem {
   // 使用 Map 存储学生信息,key 为学号,value 为学生信息字符串
   private Map<Integer, String> studentMap = new HashMap<>();
   // 添加学生
   public void addStudent(int studentNo, String name, double score, int classId) {
       String studentInfo = name + "," + score + "," + classId;
       studentMap.put(studentNo, studentInfo);
  }
   // 查询学生
   public String getStudent(int studentNo) {
       return studentMap.get(studentNo);
  }
   // 查询所有学生
   public void listAllStudents() {
       for (Map.Entry<Integer, String> entry : studentMap.entrySet()) {
           System.out.println("学号:" + entry.getKey() +
                   ",信息:" + entry.getValue());
      }
  }
}

结果一周后,甲方指着你的鼻子骂道:狗阿巴,我录入的 500 个学生信息怎么全没了?!

你一查,原来昨晚服务器重启了,导致内存里的数据全部丢失!

你汗流浃背了:看来我得把数据保存到硬盘上......

于是你连夜改代码,把数据存到了文本文件里,这下数据就不会丢失了。

但接下来,甲方提出了各种不同的查询数据需求,每个需求你都得写一堆代码逻辑,让你越来越头大。

于是你找到号称 "后端之狗" 的鱼皮求助:有没有更好的办法管理数据啊?

鱼皮笑了笑:当然要用数据库啦!

你一脸懵:数据库?那是啥?

第一阶段:认识数据库

鱼皮:数据库就像一个超级 Excel 表格,可以存储管理海量数据、快速灵活地查询和筛选数据、在多个服务器间共享数据、并且能够精确控制数据的读写权限。

你恍然大悟:啊,所以我应该用数据库来管理学生信息。🤡

鱼皮:没错,绝大多数项目的数据都存在数据库里,因此数据库是后端程序员的必备技能。

数据库主要分 2 大类:

1)关系型数据库,比如 MySQL、Oracle、PostgreSQL,适合存储相互之间有关联的数据,比如学生和班级、订单和商品。

2)非关系型数据库,比如 Redis(主要用于缓存和高速读写)、MongoDB(文档型数据库),它们在数据结构和使用场景上更灵活。

你:这么多数据库,我该学哪个呢?

鱼皮:建议新手从 MySQL 开始 ,因为它是主流的、容易入门的、开源的关系型数据库。

你:那还等什么,MySQL,启动!

鱼皮:别急,在学之前,得先了解几个数据库的基本概念。

1)数据库管理系统(DBMS):顾名思义就是用来管理数据库的系统,比如 MySQL。它把数据存储在硬盘上,断电也不会丢失。

2)数据库:一个 MySQL 系统可以管理多个数据库,比如每个项目一个库(学生系统一个库、订单系统一个库),互不干扰。

3)表:一个数据库可以有多张数据表,用来存储某一类数据。

4)记录:表由一行行记录组成,每一行就是一条数据

5)字段:每一列对应一个字段,具有名称和类型。比如姓名字段是文本类型、年龄字段是数字类型。

6)关联

这是关系型数据库的核心,表和表之间是有联系的,主要有 3 种关系。

1 对 1:比如学生表和学生档案表,一个学生对应一份档案

1 对多:比如班级表和学生表,一个班级有多个学生

多对多:比如学生表和课程表,一个学生可以选多门课,一门课也可以被多个学生选

这些表和表之间的关联形成了完整的业务系统。

你想了想:对哦,也就是说我可以根据学生关联查询到所属的班级和选修的课程。

那怎么操作数据库呢?

鱼皮:这就要用到 SQL 了。

SQL 是专门用来操作数据库的 结构化查询语言 (Structured Query Language)。

你可以用 SQL 实现各种查询,比如:

1)查询所有学生:SELECT * FROM student;

2)只查询属于某个班级的学生:SELECT * FROM student WHERE class_id = 1;

3)分组统计每个班级中所有学生的平均成绩:SELECT class_id, AVG(score) FROM student GROUP BY class_id;

4)还可以同时查询学生表和班级表,并把结果关联在一起:SELECT s.name, c.class_name FROM student s JOIN class c ON s.class_id = c.id;

此外,不同的数据库管理系统(比如 MySQL、Oracle、SQL Server)有自己的 "方言",操作这些数据库的 SQL 会有一点点小差别。

你:天呐,相当于我要多学一门语言,而且还要学方言!

鱼皮:别担心,SQL 的核心语法都是通用的。

而且你现在只需要知道 SQL 是用来操作数据库的就够了,

有时间再到我开发的 免费 SQL 学习网站 边练边学,而且后续我还会出视频专门讲 SQL 哦。

你:关注了关注了~

鱼皮:那接下来咱们就开始实战学习吧,先把 MySQL 装上并且操作一波。

第二阶段:实战应用

基础操作

机智如你,直接打开 官网 下载了 MySQL 数据库,并且成功安装运行。

但是怎么操作 MySQL 呢?

鱼皮:可以使用官方提供的 命令行工具,先输入命令,输入默认设置的用户名和密码,就能连上数据库并进行操作了。

你:root 是什么?

鱼皮:root 是数据库的超级管理员账号,拥有所有权限。

不过命令行看着不直观,我建议你装个 MySQL 可视化工具(比如 Navicat、DataGrip),能像使用 Excel 一样管理数据库,数据一目了然。

你:哇,确实方便多了!

鱼皮:接下来我带你实际操作一遍,用数据库来管理学生信息。

1)首先连接数据库

点击左上角创建连接,选择数据库的类别,然后输入数据库配置信息,点击确认,就连接成功了。

2)然后来创建一个数据库

右键点击数据库连接,选择 "新建数据库",命名为 school,点击确认,就创建成功了。

对应的 SQL 语句是 CREATE DATABASE school;

3)接下来我们要创建表

鱼皮:想一想,如果要设计一个存储学生信息的表,需要哪些字段?

你:学号、姓名、成绩、班级。

鱼皮:没错,每个字段还要指定类型。

  • 学号用 int 整数类型

  • 姓名用 varchar 文本类型

  • 成绩用 decimal 小数类型(保留 2 位小数)

  • 班级用 int 整数类型(表示班级编号)

除了类型,创建表时还要设置一些 约束 ,比如:

  • 主键:每条数据的唯一标识,一般建议每个表单独加一列 id 字段,作为主键

  • 非空:某些字段不能为空,比如姓名不能为空

  • 唯一:值不能重复,比如每个学号都是唯一的

  • 外键:建立表之间的关联关系,比如学生表的 class_id 可以设为外键,关联到班级表的 id,保证数据的完整性。但实际开发中外键存在性能问题,用的没那么多。

设计好表结构之后,点击保存,数据表就创建成功了。

对应的 SQL 语句类似这样:

复制代码
CREATE TABLE student (
  id INT PRIMARY KEY AUTO_INCREMENT,  # 主键,自动递增
  student_no INT UNIQUE NOT NULL,     # 学号,唯一且非空
  name VARCHAR(50) NOT NULL,          # 姓名,非空
  score DECIMAL(5,2),                 # 成绩,最多 5 位数字,2 位小数
  class_id INT                        # 班级编号
);

4)然后我们就可以操作数据表了。主要有 4 类核心操作 ------ 增删改查。

先插入几条学生数据:

复制代码
INSERT INTO student (student_no, name, score, class_id) 
VALUES (2024001, '小阿巴', 95.5, 1);

然后查询所有学生数据:

复制代码
SELECT * FROM student;

修改某条数据,把你的成绩改成满分:

复制代码
UPDATE student SET score = 100 WHERE student_no = 2024001;
​
SELECT * FROM student;

最后删除某条数据:

复制代码
DELETE FROM student WHERE student_no = 2024001;
​
SELECT * FROM student;

鱼皮:注意,删除掉的数据就再也找不回来了!

因此实际项目中建议使用 逻辑删除 ,就是加个 is_deleted 字段来标记数据是否失效,而不是真的删除数据,这样即使误删也能恢复。

客户端操作

你很是兴奋:用可视化工具真方便啊,但是我怎么用代码操作数据库呢?

鱼皮:主流编程语言都有操作数据库的 SDK,比如使用 Java 的 JDBC,需要先加载对应数据库的驱动、然后获取连接、编写 SQL 语句并执行、最后收集结果并关闭连接。

你挠了挠头:我就查询 1 次数据库,都要写这么多代码么?而且我根本不会写 SQL 语句啊!

鱼皮笑道:没关系,实际开发中我们会使用 ORM 对象关系映射框架 ,可以把数据库的表映射成 Java 对象,像操作对象一样操作数据库。

比如 Java 的 MyBatis 框架,可以让你用更简洁的方式执行 SQL:

复制代码
// MyBatis 方式:只需要写 SQL,框架自动处理连接和结果映射
Student student = studentMapper.selectByStudentNo(2024001);
System.out.println(student.getName());

还有它的增强版 MyBatis Plus 和 MyBatis Flex,提供了更多开箱即用的功能,连 SQL 都不用写!直接调用现成的方法,几行代码就能实现增删改查,告别 SQL Boy!

你感叹道:这才是人写的代码啊!优雅,真是优雅~

鱼皮提醒道:但是,框架不是万能的,有些复杂查询的 SQL 还要自己手写,不过现在有 AI 了,写个 SQL 还不是手拿把掐的?

你:明白了,我这就用框架重写学生管理系统。

第三阶段:数据库特性

索引

一个月后,你重写的学生管理系统正式上线,不仅得到了甲方的好评,而且很快火遍了全国高校。

你内心暗爽:数据库也不过如此嘛~

但你没想到,随着学生数据量的暴涨和表结构的扩展,你的数据库查询速度也越来越慢,光是查询某个班级的学生竟然都要等好几秒!

你有些惊讶:我这 SQL 也不复杂啊,怎么查询这么慢?

鱼皮:加个索引试试?

你:索引?那是啥?

鱼皮:索引就是数据库的目录。你现在查数据,数据库得一行一行全表扫描,数据量越大速度越慢。加了索引后,数据库可以通过索引快速定位到数据,就像通过书的目录快速翻到某一页。

你恍然大悟:对啊,老师经常按班级查询学生,不妨给班级字段添加索引。

复制代码
CREATE INDEX idx_class_id ON student(class_id);

添加索引后,你再次测试查询,竟然只要几十毫秒!

你激动得跳了起来:索引太香了,我要给所有字段都加索引~

鱼皮摆摆手:别,索引可不是越多越好!

你愣住了:为啥?

鱼皮:索引虽然能加快查询,但也有代价。

  • 一方面会增加写入数据(增删改)的开销。因为每次写入数据,索引也要更新。

  • 此外,索引本身也是数据,要占用更多的存储空间。

所以,要在经常用来查询、并且数据区分度高的字段上合理添加索引。比如班级 ID、学号这种字段适合加索引,但性别字段(只有男女两个值)就不适合。

事务

又过了几天,甲方又提新需求了。

甲方:小阿巴,有老师反馈题目判错了,需要批量把所有学生的成绩都加 5 分。

你信心满满:简单,不就是个批量更新操作么?

你写了一段代码,循环更新所有学生的成绩。

没想到,越自信 Bug 越多,功能刚刚上线,就收到了投诉:怎么有些学生的成绩改了,有些没改?

你查看了下日志,发现前面学生的成绩更新成功了,但由于网络波动,导致后面的学生都没更新。

你急坏了:咋办,这样就不公平了啊!

鱼皮看了看你的代码:这是典型的数据一致性问题,你需要用 事务 来解决。

你:啥是事务?

鱼皮:事务就是把多个操作捆绑在一起,要么全部成功,要么全部失败。

就像你给别人投币,你扣除硬币和对方增加硬币必须同时成功,不能让硬币凭空消失对吧?

你:对对对,那批量改成绩也是,要么所有学生都加 5 分,要么都不加。

鱼皮:没错,数据库事务有 4 个特性,简称 ACID:

  • 原子性(A tomicity):要么全做,要么全不做。

  • 一致性(C onsistency):数据从一个正确状态到另一个正确状态。比如转账时,A 扣钱和 B 加钱的总和不变。

  • 隔离性(I solation):多个事务互不干扰。

  • 持久性(D urability):事务完成后,数据永久保存。

你:那怎么使用事务呢?

鱼皮:如果直接用原始的 JDBC,需要手动控制事务,比较麻烦。

但如果在 Spring 框架中,只需要加一个 @Transactional 注解就搞定了:

Spring 会自动帮你管理事务。如果中间任何一步出错,抛出了指定的异常,整个事务会自动回滚,将数据恢复到原来的状态,保证要么所有学生都加分成功,要么都不加。

你:原来这么简单啊,我这就用事务重写代码!

其他

鱼皮:MySQL 还有一些其他特性,比如视图可以用来简化复杂查询、存储过程可以批量执行 SQL、触发器可以自动触发操作。

1)视图:视图是一个虚拟表,把复杂查询封装起来重复使用。比如你经常要统计每个班级的平均成绩,每次都写一长串 SQL 太麻烦,可以创建一个视图,以后直接查视图就行。

2)存储过程:可以批量执行 SQL。比如每天定时同步数据,写个存储过程,定时调用就行。

3)触发器:可以自动触发操作。比如每次添加用户,自动生成一条操作日志,不用手动写代码。

你感叹道:原来数据库还有这么多功能,我学不完了啊......

鱼皮笑了:别担心,这些在实际开发中用得不多,先简单了解就好。

第四阶段:生产环境实践

几年后,你已经成为小有名气的 "学生管理系统大师",还成立了自己的工作室。

没事儿就对着新来的实习生阿坤吹牛皮:你阿巴哥我啊,精通数据库,索引、事务耍的贼溜儿~

然而某天上午,学校的运维同学打来电话:阿巴阿巴,系统出问题了,所有操作都一直 转圈、超时 ! 好像是数据库卡死了!

你大惊:什么?!我都加索引了,还能卡死?

emmm...... 对了,我想到了!

赶紧重启数据库,重启解决所有问题!嘿嘿嘿哈哈哈哈~

结果重启没多久,数据库又卡死了!

你彻底懵了:呜呜呜,怎么办啊!

这时,你身旁的阿坤突然鸡叫起来:我来!

为什么系统会崩溃?

阿坤:我们先看看为什么系统会崩溃?

开启 MySQL 的慢查询日志功能,有两种方式。

1)通过 SQL 命令(临时开启)

复制代码
# 开启慢查询日志功能
SET GLOBAL slow_query_log = 1;
​
# 设置慢查询阈值(超过几秒算是慢查询)
SET GLOBAL long_query_time = 5;
​
# 修改日志文件位置(可选)
SET GLOBAL slow_query_log_file = '/path/to/slow.log';

2)修改配置文件(永久生效)

复制代码
# 在 [mysqld] 部分设置参数
slow_query_log = 1
long_query_time = 5
slow_query_log_file = /path/to/slow.log

你看,有些 SQL 语句执行了几十秒!

使用 Explain 命令分析下这些查询,原来没有正确使用索引,导致了全表扫描,把数据库拖垮了。

这些慢查询就是罪魁祸首,它们会 长时间霸占数据库连接和 CPU 资源 。当大量用户同时执行慢查询,数据库连接池很快被耗尽,新的请求因为无法获取连接、全部阻塞,导致数据库 "卡死"。

你惭愧地低下头:我知道了,生产环境一定要开启慢查询日志,及时发现慢 SQL 并优化。

数据丢失了怎么办?

屋漏偏逢连夜雨,你很快又收到了投诉,说是有的学生数据丢失了!

你很是疑惑:MySQL 不是有日志(Redo Log 和 Binlog)来保证数据持久性吗?怎么会丢数据呢?

经过排查,原来是服务器的硬盘被一个学生不小心踹坏了!

你难受得像持矢了一样:真是人在家中坐,Bug 天上来。

唉,我怎么把数据找回来啊?

阿坤:别怕,幸好鱼皮哥之前设置了备份。一方面定期做 全量备份 ,比如利用 mysqldump 工具每天凌晨备份一次并发送到其他服务器上;再配合 增量备份 ,利用 Binlog(二进制日志)记录每次的数据修改操作,这样即使数据库崩了,也能恢复到最近的状态。

怎么保证系统不会再崩?

你松了一口气:那怎么保证数据库不会再宕机呢?

阿坤:可以搭建 MySQL 高可用集群,典型的是 一主多从 架构。

主库(Master)专门负责写操作(增删改),并通过 Binlog 记录每一次数据变更操作。

从库(Slave) 拉取主库的 Binlog 到本地文件中,然后回放数据变更操作,实现数据同步。我们可以利用从库来承担绝大部分的读操作,这叫 读写分离 ,能大大提升并发能力。

当主库出现故障时,利用 MHA 等工具,自动将一个从库提升为新的主库,并调整其他从库的指向,实现故障的自动切换。

数据量大了怎么办?

你很是惊讶:之前完全没听说过这些啊......

阿坤用看流浪狗的眼神看了你一眼:阿巴哥哥,如果数据量特别大,一个库存不下怎么办?

你哑口无言:阿巴阿巴......

阿坤笑了:当然是 分库分表 啦!比如

1)水平拆分:把同一张表的数据分散到多个表或多个库中。比如根据学生 ID 的尾号,奇数的存到表 1,偶数的存到表 2。

2)垂直拆分:按业务功能来拆分库,比如把学生基本信息、成绩信息、选课信息分别存到不同的库中。

你彻底服了:妙啊,这样就能存储海量数据了!

其他实践

这时鱼皮走过来拍了拍阿坤的肩膀:小伙子年轻有为啊!

小阿巴,MySQL 生产环境实践的知识点还有很多。比如:

1)权限管理:不要所有人都用 root 账号,风险太大,要给不同的人分配不同的权限。

2)云数据库服务:提供了现成的 MySQL 集群架构、监控系统、自动备份、数据迁移等,比自己运维省心多了。

3)调优技巧:硬件优化、数据库配置优化、库表设计优化、SQL 优化、连接池优化等等。

4)常见问题:还有死锁排查、大表的在线变更、数据迁移、主从延迟处理等等,遇到了再去解决。

你羞愧地抬不起头:我以为自己已经掌握了数据库,原来只是学了个皮毛......

第五阶段:深入底层原理

于是,你主动找到阿坤:我想深入学习 MySQL,不能只停留在会用的层面,请问怎么学习底层原理啊?

阿坤有些惊讶:咦?你不 背八股文 的么?刷刷题就好了呀!

你震惊了:现在的实习生,竟然恐怖如斯!

鱼皮:阿坤你别逗他了,其实我们可以带着问题学习。比如 MySQL 是如何实现高效查询的

你想了想:加索引?

鱼皮:对,但这只是使用层面。底层实现有很多技术,比如高效的存储引擎(InnoDB)、优秀的索引结构(B+ 树)、缓冲池机制、查询优化器等等。

比如我考考你,下面两个 SQL 语句哪个执行更快?

复制代码
# SQL 1: 使用 OR
SELECT * FROM student WHERE class_id = 1 OR class_id = 2;
​
# SQL 2: 使用 IN
SELECT * FROM student WHERE class_id IN (1, 2);

你:额...... 第 2 个?因为它更简短。

鱼皮:哼哼,答案是 几乎一样快 !因为 MySQL 的查询优化器非常智能,它会分析语句、将它们处理成相同的逻辑结构,再去执行。

这就是 MySQL 能高效查询的原因之一,带着这些问题去阅读相关文章,或者直接像阿坤说的刷一刷 MySQL 面试题,就能快速学会很多核心知识点。

如果想系统学习,可以看看《MySQL 是怎样运行的》、《高性能 MySQL》这几本书。

要记住,学习底层原理不只是为了应付面试,而是为了更好地使用 MySQL,遇到问题时能够快速定位和解决。

你:好的,我这就去学!

结尾

若干年后,你已经成为了大厂的数据库专家。不仅能熟练设计库表、优化性能,搭个 MySQL 集群也是手拿把掐的。

!

你也像鱼皮当时一样,耐心地给新人分享学习数据库的经验:数据库是实战型技术,一定要多动手实践。

再次遇到鱼皮是在一条昏暗的小巷,此时的他年过 35,灰头土脸。你什么都没说,只是给他点了个赞,不打扰,是你的温柔。

更详细的 MySQL 数据库学习路线,可以在编程导航免费阅读哦。

更多编程学习资源

相关推荐
启山智软13 小时前
【中大企业选择源码部署商城系统】
java·spring·商城开发
我真的是大笨蛋13 小时前
深度解析InnoDB如何保障Buffer与磁盘数据一致性
java·数据库·sql·mysql·性能优化
怪兽源码13 小时前
基于SpringBoot的选课调查系统
java·spring boot·后端·选课调查系统
恒悦sunsite14 小时前
Redis之配置只读账号
java·redis·bootstrap
梦里小白龙14 小时前
java 通过Minio上传文件
java·开发语言
人道领域14 小时前
javaWeb从入门到进阶(SpringBoot事务管理及AOP)
java·数据库·mysql
sheji526114 小时前
JSP基于信息安全的读书网站79f9s--程序+源码+数据库+调试部署+开发环境
java·开发语言·数据库·算法
毕设源码-邱学长14 小时前
【开题答辩全过程】以 基于Java Web的电子商务网站的用户行为分析与个性化推荐系统为例,包含答辩的问题和答案
java·开发语言
摇滚侠14 小时前
Java项目教程《尚庭公寓》java项目从开发到部署,技术储备,MybatisPlus、MybatisX
java·开发语言
€81114 小时前
Java入门级教程24——Vert.x的学习
java·开发语言·学习·thymeleaf·数据库操作·vert.x的路由处理机制·datadex实战