MySQL 从入门到删库跑路,保姆级教程!
<p class="md-end-block md-heading"><span class="md-plain">你是小阿巴,刚入行的程序员。</span></p><p class="md-end-block md-p"><span class="md-image md-img-loaded" data-src="https://pic.yupi.icu/1/1764309412825-c8e7c87e-d701-48d3-a5e2-45efde2fa302.png"><img src="https://pic.yupi.icu/1/1764309412825-c8e7c87e-d701-48d3-a5e2-45efde2fa302.png"></span></p>
<p class="md-end-block md-p"><span class="md-plain">这天,你接到一个私活:帮学校做个学生管理系统,要能管理学生信息、记录成绩、统计数据。</span></p>
<p class="md-end-block md-p"><span class="md-plain">你一听,这不简单吗?用 Java 写个程序,把数据存到 Map 里就搞定了。</span></p>
<pre class="md-fences md-end-block ty-contain-cm modeLoaded"><span><span class="cm-keyword">public <span class="cm-keyword">class <span class="cm-def">StudentManagementSystem {<br><span> <span class="cm-comment">// 使用 Map 存储学生信息,key 为学号,value 为学生信息字符串<br><span> <span class="cm-keyword">private <span class="cm-variable">Map<span class="cm-operator"><<span class="cm-variable-3">Integer, <span class="cm-variable-3">String<span class="cm-operator">> <span class="cm-variable">studentMap <span class="cm-operator">= <span class="cm-keyword">new <span class="cm-variable">HashMap<span class="cm-operator"><>();<br><span> <span class="cm-comment">// 添加学生<br><span> <span class="cm-keyword">public <span class="cm-variable-3">void <span class="cm-variable">addStudent(<span class="cm-variable-3">int <span class="cm-variable">studentNo, <span class="cm-variable-3">String <span class="cm-variable">name, <span class="cm-variable-3">double <span class="cm-variable">score, <span class="cm-variable-3">int <span class="cm-variable">classId) {<br><span> <span class="cm-variable-3">String <span class="cm-variable">studentInfo <span class="cm-operator">= <span class="cm-variable">name <span class="cm-operator">+ <span class="cm-string">"," <span class="cm-operator">+ <span class="cm-variable">score <span class="cm-operator">+ <span class="cm-string">"," <span class="cm-operator">+ <span class="cm-variable">classId;<br><span> <span class="cm-variable">studentMap.<span class="cm-variable">put(<span class="cm-variable">studentNo, <span class="cm-variable">studentInfo);<br><span> }<br><span> <span class="cm-comment">// 查询学生<br><span> <span class="cm-keyword">public <span class="cm-variable-3">String <span class="cm-variable">getStudent(<span class="cm-variable-3">int <span class="cm-variable">studentNo) {<br><span> <span class="cm-keyword">return <span class="cm-variable">studentMap.<span class="cm-variable">get(<span class="cm-variable">studentNo);<br><span> }<br><span> <span class="cm-comment">// 查询所有学生<br><span> <span class="cm-keyword">public <span class="cm-variable-3">void <span class="cm-variable">listAllStudents() {<br><span> <span class="cm-keyword">for (<span class="cm-variable">Map.<span class="cm-variable">Entry<span class="cm-operator"><<span class="cm-variable-3">Integer, <span class="cm-variable-3">String<span class="cm-operator">> <span class="cm-variable">entry : <span class="cm-variable">studentMap.<span class="cm-variable">entrySet()) {<br><span> <span class="cm-variable">System.<span class="cm-variable">out.<span class="cm-variable">println(<span class="cm-string">"学号:" <span class="cm-operator">+ <span class="cm-variable">entry.<span class="cm-variable">getKey() <span class="cm-operator">+<br><span> <span class="cm-string">",信息:" <span class="cm-operator">+ <span class="cm-variable">entry.<span class="cm-variable">getValue());<br><span> }<br><span> }<br><span>}</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></pre>
<p class="md-end-block md-p"> </p>
<p class="md-end-block md-p"><span class="md-plain">结果一周后,甲方指着你的鼻子骂道:狗阿巴,我录入的 500 个学生信息怎么全没了?!</span></p>
<p class="md-end-block md-p"><span class="md-plain">你一查,原来昨晚服务器重启了,导致内存里的数据全部丢失!</span></p>
<p class="md-end-block md-p"><span class="md-plain">你汗流浃背了:看来我得把数据保存到硬盘上……</span></p>
<p class="md-end-block md-p"><span class="md-plain">于是你连夜改代码,把数据存到了文本文件里,这下数据就不会丢失了。</span></p>
<p class="md-end-block md-p"><span class="md-image md-img-loaded" data-src="https://pic.yupi.icu/1/1764309480122-a6c84286-e417-49eb-8df3-efe640acdd85.png"><img src="https://pic.yupi.icu/1/1764309480122-a6c84286-e417-49eb-8df3-efe640acdd85.png"></span></p>
<p class="md-end-block md-p"><span class="md-plain">但接下来,甲方提出了各种不同的查询数据需求,每个需求你都得写一堆代码逻辑,让你越来越头大。</span></p>
<p class="md-end-block md-p"><span class="md-image md-img-loaded" data-src="https://pic.yupi.icu/1/1764309508479-150b4552-103c-49d2-a49b-c849ddd78cc6.png"><img src="https://pic.yupi.icu/1/1764309508479-150b4552-103c-49d2-a49b-c849ddd78cc6.png"></span></p>
<p class="md-end-block md-p"><span class="md-plain">于是你找到号称 “后端之狗” 的鱼皮求助:有没有更好的办法管理数据啊?</span></p>
<p class="md-end-block md-p"><span class="md-plain">鱼皮笑了笑:当然要用数据库啦!</span></p>
<p class="md-end-block md-p"><span class="md-plain">你一脸懵:数据库?那是啥?</span></p>
<p class="md-end-block md-p"> </p>
<p class="md-end-block md-p"> </p>
<h2 class="md-end-block md-heading"><span class="md-plain">第一阶段:认识数据库</span></h2>
<p class="md-end-block md-p"><span class="md-plain">鱼皮:数据库就像一个超级 Excel 表格,可以存储管理海量数据、快速灵活地查询和筛选数据、在多个服务器间共享数据、并且能够精确控制数据的读写权限。</span></p>
<p class="md-end-block md-p"><span class="md-image md-img-loaded" data-src="https://pic.yupi.icu/1/1764309543262-9080b74e-ceb1-4804-8c07-be877a9615d7.png"><img src="https://pic.yupi.icu/1/1764309543262-9080b74e-ceb1-4804-8c07-be877a9615d7.png"></span></p>
<p class="md-end-block md-p"><span class="md-plain">你恍然大悟:啊,所以我应该用数据库来管理学生信息。🤡</span></p>
<p class="md-end-block md-p"><span class="md-plain">鱼皮:没错,绝大多数项目的数据都存在数据库里,因此数据库是后端程序员的必备技能。</span></p>
<p class="md-end-block md-p"><span class="md-plain">数据库主要分 2 大类:</span></p>
<p class="md-end-block md-p"><span class="md-plain">1)关系型数据库,比如 MySQL、Oracle、PostgreSQL,适合存储相互之间有关联的数据,比如学生和班级、订单和商品。</span></p>
<p class="md-end-block md-p"><span class="md-image md-img-loaded" data-src="https://pic.yupi.icu/1/1764309581505-2ff17977-695f-4d7c-a779-b5d35ad99d6b.png"><img src="https://pic.yupi.icu/1/1764309581505-2ff17977-695f-4d7c-a779-b5d35ad99d6b.png"></span></p>
<p class="md-end-block md-p"><span class="md-plain">2)非关系型数据库,比如 Redis(主要用于缓存和高速读写)、MongoDB(文档型数据库),它们在数据结构和使用场景上更灵活。</span></p>
<p class="md-end-block md-p"><span class="md-image md-img-loaded" data-src="https://pic.yupi.icu/1/1764309606178-1af81d82-b320-4bed-9c97-5dfe3847d8d3.png"><img src="https://pic.yupi.icu/1/1764309606178-1af81d82-b320-4bed-9c97-5dfe3847d8d3.png"></span></p>
<p class="md-end-block md-p"> </p>
<p class="md-end-block md-p"><span class="md-plain">你:这么多数据库,我该学哪个呢?</span></p>
<p class="md-end-block md-p"><span class="md-plain">鱼皮:<span class="md-pair-s "><strong>建议新手从 MySQL 开始</strong><span class="md-plain">,因为它是主流的、容易入门的、开源的关系型数据库。</span></span></span></p>
<p class="md-end-block md-p"><span class="md-plain">你:那还等什么,MySQL,启动!</span></p>
<p class="md-end-block md-p"><span class="md-plain">鱼皮:别急,在学之前,得先了解几个数据库的基本概念。</span></p>
<p class="md-end-block md-p"><span class="md-plain">1)数据库管理系统(DBMS):顾名思义就是用来管理数据库的系统,比如 MySQL。它把数据存储在硬盘上,断电也不会丢失。</span></p>
<p class="md-end-block md-p"><span class="md-plain">2)数据库:一个 MySQL 系统可以管理多个数据库,比如每个项目一个库(学生系统一个库、订单系统一个库),互不干扰。</span></p>
<p class="md-end-block md-p"><span class="md-plain">3)表:一个数据库可以有多张数据表,用来存储某一类数据。</span></p>
<p class="md-end-block md-p"><span class="md-plain">4)记录:表由一行行记录组成,每一行就是一条数据</span></p>
<p class="md-end-block md-p"><span class="md-plain">5)字段:每一列对应一个字段,具有名称和类型。比如姓名字段是文本类型、年龄字段是数字类型。</span></p>
<p class="md-end-block md-p"><span class="md-image md-img-loaded" data-src="https://pic.yupi.icu/1/1764309634016-545707ef-1cef-4d9c-a726-b4a76b03483f.png"><img src="https://pic.yupi.icu/1/1764309634016-545707ef-1cef-4d9c-a726-b4a76b03483f.png"></span></p>
<p class="md-end-block md-p"><span class="md-plain">6)关联</span></p>
<p class="md-end-block md-p"><span class="md-plain">这是关系型数据库的核心,表和表之间是有联系的,主要有 3 种关系。</span></p>
<p class="md-end-block md-p"><span class="md-plain">1 对 1:比如学生表和学生档案表,一个学生对应一份档案</span></p>
<p class="md-end-block md-p"><span class="md-image md-img-loaded" data-src="https://pic.yupi.icu/1/1764309690300-1170c585-58b3-41a7-84bc-3cea8284825b.png"><img src="https://pic.yupi.icu/1/1764309690300-1170c585-58b3-41a7-84bc-3cea8284825b.png"></span></p>
<p class="md-end-block md-p"><span class="md-plain">1 对多:比如班级表和学生表,一个班级有多个学生</span></p>
<p class="md-end-block md-p"><span class="md-image md-img-loaded" data-src="https://pic.yupi.icu/1/1764309700539-c1df953e-f389-4b2d-9364-279aa4b7087e.png"><img src="https://pic.yupi.icu/1/1764309700539-c1df953e-f389-4b2d-9364-279aa4b7087e.png"></span></p>
<p class="md-end-block md-p"><span class="md-plain">多对多:比如学生表和课程表,一个学生可以选多门课,一门课也可以被多个学生选</span></p>
<p class="md-end-block md-p"><span class="md-image md-img-loaded" data-src="https://pic.yupi.icu/1/1764309787623-3dece5ff-da5b-47ef-a955-5470e997d7e1.png"><img src="https://pic.yupi.icu/1/1764309787623-3dece5ff-da5b-47ef-a955-5470e997d7e1.png"></span></p>
<p class="md-end-block md-p"><span class="md-plain">这些表和表之间的关联形成了完整的业务系统。</span></p>
<p class="md-end-block md-p"><span class="md-plain">你想了想:对哦,也就是说我可以根据学生关联查询到所属的班级和选修的课程。</span></p>
<p class="md-end-block md-p"><span class="md-plain">那怎么操作数据库呢?</span></p>
<p class="md-end-block md-p"><span class="md-plain">鱼皮:这就要用到 SQL 了。</span></p>
<p class="md-end-block md-p"><span class="md-plain">SQL 是专门用来操作数据库的 <span class="md-pair-s "><strong>结构化查询语言</strong><span class="md-plain">(Structured Query Language)。</span></span></span></p>
<p class="md-end-block md-p"><span class="md-plain">你可以用 SQL 实现各种查询,比如:</span></p>
<p class="md-end-block md-p"><span class="md-plain">1)查询所有学生:<span class="md-pair-s"><code>SELECT * FROM student;</code></span></span></p>
<p class="md-end-block md-p"><span class="md-plain">2)只查询属于某个班级的学生:<span class="md-pair-s"><code>SELECT * FROM student WHERE class_id = 1;</code></span></span></p>
<p class="md-end-block md-p"><span class="md-image md-img-loaded" data-src="https://pic.yupi.icu/1/1764309817802-808ab9c2-4ec0-44bb-b971-eefc0e876ea9.png"><img src="https://pic.yupi.icu/1/1764309817802-808ab9c2-4ec0-44bb-b971-eefc0e876ea9.png"></span></p>
<p class="md-end-block md-p"><span class="md-plain">3)分组统计每个班级中所有学生的平均成绩:<span class="md-pair-s"><code>SELECT class_id, AVG(score) FROM student GROUP BY class_id;</code></span></span></p>
<p class="md-end-block md-p"><span class="md-image md-img-loaded" data-src="https://pic.yupi.icu/1/1764309841228-ff024bfd-c4b2-4c21-8351-b4d95711f476.png"><img src="https://pic.yupi.icu/1/1764309841228-ff024bfd-c4b2-4c21-8351-b4d95711f476.png"></span></p>
<p class="md-end-block md-p"><span class="md-plain">4)还可以同时查询学生表和班级表,并把结果关联在一起:<span class="md-pair-s"><code>SELECT s.name, c.class_name FROM student s JOIN class c ON s.class_id = c.id;</code></span></span></p>
<p class="md-end-block md-p"><span class="md-image md-img-loaded" data-src="https://pic.yupi.icu/1/1764309830083-c4a38ad0-cd7e-4237-b0e0-31580d165db6.png"><img src="https://pic.yupi.icu/1/1764309830083-c4a38ad0-cd7e-4237-b0e0-31580d165db6.png"></span></p>
<p class="md-end-block md-p"><span class="md-plain">此外,不同的数据库管理系统(比如 MySQL、Oracle、SQL Server)有自己的 “方言”,操作这些数据库的 SQL 会有一点点小差别。</span></p>
<p class="md-end-block md-p"><span class="md-image md-img-loaded" data-src="https://pic.yupi.icu/1/1764309854927-95ba6a02-9816-46e2-a18d-d4d9778a63c7.png"><img src="https://pic.yupi.icu/1/1764309854927-95ba6a02-9816-46e2-a18d-d4d9778a63c7.png"></span></p>
<p class="md-end-block md-p"><span class="md-plain">你:天呐,相当于我要多学一门语言,而且还要学方言!</span></p>
<p class="md-end-block md-p"><span class="md-plain">鱼皮:别担心,SQL 的核心语法都是通用的。</span></p>
<p class="md-end-block md-p"><span class="md-image md-img-loaded" data-src="https://pic.yupi.icu/1/1764309925307-eddf9ad2-582c-4b42-8806-de0ce5c1771c.png"><img src="https://pic.yupi.icu/1/1764309925307-eddf9ad2-582c-4b42-8806-de0ce5c1771c.png"></span></p>
<p class="md-end-block md-p"><span class="md-plain">而且你现在只需要知道 SQL 是用来操作数据库的就够了,</span></p>
<p class="md-end-block md-p"><span class="md-plain">有时间再到我开发的 <span class="md-meta-i-cmd-link"><span class="md-plain">免费 SQL 学习网站</span><span class="md-plain"> 边练边学,而且后续我还会出视频专门讲 SQL 哦。</span></span></span></p>
<p class="md-end-block md-p"><span class="md-image md-img-loaded" data-src="https://pic.yupi.icu/1/1764300059934-9c98a718-8c6a-44d1-91f2-6f161c8d1028.png"><img src="https://pic.yupi.icu/1/1764300059934-9c98a718-8c6a-44d1-91f2-6f161c8d1028.png"></span></p>
<p class="md-end-block md-p"> </p>
<p class="md-end-block md-p"><span class="md-plain">你:关注了关注了~</span></p>
<p class="md-end-block md-p"><span class="md-plain">鱼皮:那接下来咱们就开始实战学习吧,先把 MySQL 装上并且操作一波。</span></p>
<p class="md-end-block md-p"> </p>
<h2 class="md-end-block md-heading"><span class="md-plain">第二阶段:实战应用</span></h2>
<h3 class="md-end-block md-heading"><span class="md-plain">基础操作</span></h3>
<p class="md-end-block md-p"><span class="md-plain">机智如你,直接打开 <span class="md-meta-i-cmd-link"><span class="md-plain">官网</span><span class="md-plain"> 下载了 MySQL 数据库,并且成功安装运行。</span></span></span></p>
<p class="md-end-block md-p"><span class="md-image md-img-loaded" data-src="https://pic.yupi.icu/1/1764309951612-b9057003-c0d7-43a9-8e91-8989beccafcb.png"><img src="https://pic.yupi.icu/1/1764309951612-b9057003-c0d7-43a9-8e91-8989beccafcb.png"></span></p>
<p class="md-end-block md-p"> </p>
<p class="md-end-block md-p"><span class="md-plain">但是怎么操作 MySQL 呢?</span></p>
<p class="md-end-block md-p"><span class="md-plain">鱼皮:可以使用官方提供的 <span class="md-meta-i-cmd-link"><span class="md-plain">命令行工具</span><span class="md-plain">,先输入命令,输入默认设置的用户名和密码,就能连上数据库并进行操作了。</span></span></span></p>
<p class="md-end-block md-p"><span class="md-image md-img-loaded" data-src="https://pic.yupi.icu/1/1764309969072-abce2dee-c365-4ec0-ad26-e8157157525b.png"><img src="https://pic.yupi.icu/1/1764309969072-abce2dee-c365-4ec0-ad26-e8157157525b.png"></span></p>
<p class="md-end-block md-p"><span class="md-plain">你:root 是什么?</span></p>
<p class="md-end-block md-p"><span class="md-plain">鱼皮:root 是数据库的超级管理员账号,拥有所有权限。</span></p>
<p class="md-end-block md-p"><span class="md-plain">不过命令行看着不直观,我建议你装个 MySQL 可视化工具(比如 <span class="md-meta-i-cmd-link"><span class="md-plain">Navicat</span><span class="md-plain">、DataGrip),能像使用 Excel 一样管理数据库,数据一目了然。</span></span></span></p>
<p class="md-end-block md-p"><span class="md-image md-img-loaded" data-src="https://pic.yupi.icu/1/1764310001315-f83e0291-e514-4048-a7b1-17638b0d825b.png"><img src="https://pic.yupi.icu/1/1764310001315-f83e0291-e514-4048-a7b1-17638b0d825b.png"></span></p>
<p class="md-end-block md-p"><span class="md-plain">你:哇,确实方便多了!</span></p>
<p class="md-end-block md-p"><span class="md-plain">鱼皮:接下来我带你实际操作一遍,用数据库来管理学生信息。</span></p>
<p class="md-end-block md-p"><span class="md-plain">1)首先连接数据库</span></p>
<p class="md-end-block md-p"><span class="md-plain">点击左上角创建连接,选择数据库的类别,然后输入数据库配置信息,点击确认,就连接成功了。</span></p>
<p class="md-end-block md-p"><span class="md-image md-img-loaded" data-src="https://pic.yupi.icu/1/1764310035980-4b8d60c8-0e87-4826-9990-7dc29d464185.png"><img src="https://pic.yupi.icu/1/1764310035980-4b8d60c8-0e87-4826-9990-7dc29d464185.png"></span></p>
<p class="md-end-block md-p"> </p>
<p class="md-end-block md-p"><span class="md-plain">2)然后来创建一个数据库</span></p>
<p class="md-end-block md-p"><span class="md-plain">右键点击数据库连接,选择 “新建数据库”,命名为 school,点击确认,就创建成功了。</span></p>
<p class="md-end-block md-p"><span class="md-plain">对应的 SQL 语句是 <span class="md-pair-s"><code>CREATE DATABASE school;</code></span></span></p>
<p class="md-end-block md-p"><span class="md-image md-img-loaded" data-src="https://pic.yupi.icu/1/1764310067116-85414957-f7e5-49ba-90d0-7d4d474b6c02.png"><img src="https://pic.yupi.icu/1/1764310067116-85414957-f7e5-49ba-90d0-7d4d474b6c02.png"></span></p>
<p class="md-end-block md-p"> </p>
<p class="md-end-block md-p"><span class="md-plain">3)接下来我们要创建表</span></p>
<p class="md-end-block md-p"><span class="md-plain">鱼皮:想一想,如果要设计一个存储学生信息的表,需要哪些字段?</span></p>
<p class="md-end-block md-p"><span class="md-plain">你:学号、姓名、成绩、班级。</span></p>
<p class="md-end-block md-p"><span class="md-plain">鱼皮:没错,每个字段还要指定类型。</span></p>
<ul class="ul-list" data-mark="-">
<li class="md-list-item">
<p class="md-end-block md-p"><span class="md-plain">学号用 int 整数类型</span></p>
</li>
<li class="md-list-item">
<p class="md-end-block md-p"><span class="md-plain">姓名用 varchar 文本类型</span></p>
</li>
<li class="md-list-item">
<p class="md-end-block md-p"><span class="md-plain">成绩用 decimal 小数类型(保留 2 位小数)</span></p>
</li>
<li class="md-list-item">
<p class="md-end-block md-p"><span class="md-plain">班级用 int 整数类型(表示班级编号)</span></p>
</li>
</ul>
<p class="md-end-block md-p"><span class="md-image md-img-loaded" data-src="https://pic.yupi.icu/1/1764310095212-bbc398bd-6ab7-4b87-882a-9e03dfe8564d.png"><img src="https://pic.yupi.icu/1/1764310095212-bbc398bd-6ab7-4b87-882a-9e03dfe8564d.png"></span></p>
<p class="md-end-block md-p"><span class="md-plain">除了类型,创建表时还要设置一些 <span class="md-pair-s "><strong>约束</strong><span class="md-plain">,比如:</span></span></span></p>
<ul class="ul-list" data-mark="-">
<li class="md-list-item">
<p class="md-end-block md-p"><span class="md-plain">主键:每条数据的唯一标识,一般建议每个表单独加一列 id 字段,作为主键</span></p>
</li>
<li class="md-list-item">
<p class="md-end-block md-p"><span class="md-plain">非空:某些字段不能为空,比如姓名不能为空</span></p>
</li>
<li class="md-list-item">
<p class="md-end-block md-p"><span class="md-plain">唯一:值不能重复,比如每个学号都是唯一的</span></p>
</li>
<li class="md-list-item">
<p class="md-end-block md-p"><span class="md-plain">外键:建立表之间的关联关系,比如学生表的 class_id 可以设为外键,关联到班级表的 id,保证数据的完整性。但实际开发中外键存在性能问题,用的没那么多。</span></p>
</li>
</ul>
<p class="md-end-block md-p"><span class="md-image md-img-loaded" data-src="https://pic.yupi.icu/1/1764310113637-066ce3e5-a9fd-43e8-8431-95f6db61ed14.png"><img src="https://pic.yupi.icu/1/1764310113637-066ce3e5-a9fd-43e8-8431-95f6db61ed14.png"></span></p>
<p class="md-end-block md-p"><span class="md-plain">设计好表结构之后,点击保存,数据表就创建成功了。</span></p>
<p class="md-end-block md-p"><span class="md-plain">对应的 SQL 语句类似这样:</span></p>
<pre class="md-fences md-end-block ty-contain-cm modeLoaded"><span><span class="cm-keyword">CREATE <span class="cm-keyword">TABLE student <span class="cm-bracket">(<br><span> id <span class="cm-type">INT <span class="cm-keyword">PRIMARY <span class="cm-keyword">KEY <span class="cm-keyword">AUTO_INCREMENT<span class="cm-punctuation">, <span class="cm-comment"># 主键,自动递增<br><span> student_no <span class="cm-type">INT <span class="cm-keyword">UNIQUE <span class="cm-keyword">NOT <span class="cm-atom">NULL<span class="cm-punctuation">, <span class="cm-comment"># 学号,唯一且非空<br><span> name <span class="cm-type">VARCHAR<span class="cm-bracket">(<span class="cm-number">50<span class="cm-bracket">) <span class="cm-keyword">NOT <span class="cm-atom">NULL<span class="cm-punctuation">, <span class="cm-comment"># 姓名,非空<br><span> score <span class="cm-type">DECIMAL<span class="cm-bracket">(<span class="cm-number">5<span class="cm-punctuation">,<span class="cm-number">2<span class="cm-bracket">)<span class="cm-punctuation">, <span class="cm-comment"># 成绩,最多 5 位数字,2 位小数<br><span> class_id <span class="cm-type">INT <span class="cm-comment"># 班级编号<br><span><span class="cm-bracket">)<span class="cm-punctuation">;</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></pre>
<p class="md-end-block md-p"> </p>
<p class="md-end-block md-p"><span class="md-plain">4)然后我们就可以操作数据表了。主要有 4 类核心操作 —— 增删改查。</span></p>
<p class="md-end-block md-p"><span class="md-plain">先插入几条学生数据:</span></p>
<pre class="md-fences md-end-block ty-contain-cm modeLoaded"><span><span class="cm-keyword">INSERT <span class="cm-keyword">INTO student <span class="cm-bracket">(student_no<span class="cm-punctuation">, name<span class="cm-punctuation">, score<span class="cm-punctuation">, class_id<span class="cm-bracket">) <br><span><span class="cm-keyword">VALUES <span class="cm-bracket">(<span class="cm-number">2024001<span class="cm-punctuation">, <span class="cm-string">'小阿巴'<span class="cm-punctuation">, <span class="cm-number">95.5<span class="cm-punctuation">, <span class="cm-number">1<span class="cm-bracket">)<span class="cm-punctuation">;</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></pre>
<p class="md-end-block md-p"><span class="md-plain">然后查询所有学生数据:</span></p>
<pre class="md-fences md-end-block ty-contain-cm modeLoaded"><span><span class="cm-keyword">SELECT <span class="cm-operator">* <span class="cm-keyword">FROM student<span class="cm-punctuation">;</span></span></span></span></span></pre>
<p class="md-end-block md-p"><span class="md-image md-img-loaded" data-src="https://pic.yupi.icu/1/1764310162388-fa5468e1-e7d4-4819-aef3-51cc261ba367.png"><img src="https://pic.yupi.icu/1/1764310162388-fa5468e1-e7d4-4819-aef3-51cc261ba367.png"></span></p>
<p class="md-end-block md-p"><span class="md-plain">修改某条数据,把你的成绩改成满分:</span></p>
<pre class="md-fences md-end-block ty-contain-cm modeLoaded"><span><span class="cm-keyword">UPDATE student <span class="cm-keyword">SET score <span class="cm-operator">= <span class="cm-number">100 <span class="cm-keyword">WHERE student_no <span class="cm-operator">= <span class="cm-number">2024001<span class="cm-punctuation">;<br><span><span><br><span><span class="cm-keyword">SELECT <span class="cm-operator">* <span class="cm-keyword">FROM student<span class="cm-punctuation">;</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></pre>
<p class="md-end-block md-p"><span class="md-plain">最后删除某条数据:</span></p>
<pre class="md-fences md-end-block ty-contain-cm modeLoaded"><span><span class="cm-keyword">DELETE <span class="cm-keyword">FROM student <span class="cm-keyword">WHERE student_no <span class="cm-operator">= <span class="cm-number">2024001<span class="cm-punctuation">;<br><span><span><br><span><span class="cm-keyword">SELECT <span class="cm-operator">* <span class="cm-keyword">FROM student<span class="cm-punctuation">;</span></span></span></span></span></span></span></span></span></span></span></span></span></span></pre>
<p class="md-end-block md-p"><span class="md-image md-img-loaded" data-src="https://pic.yupi.icu/1/1764310177758-f9d9337b-cd99-4af6-9ffd-5d8397774a87.png"><img src="https://pic.yupi.icu/1/1764310177758-f9d9337b-cd99-4af6-9ffd-5d8397774a87.png"></span></p>
<p class="md-end-block md-p"><span class="md-plain">鱼皮:注意,删除掉的数据就再也找不回来了!</span></p>
<p class="md-end-block md-p"><span class="md-plain">因此实际项目中建议使用 <span class="md-pair-s "><strong>逻辑删除</strong><span class="md-plain">,就是加个 <span class="md-pair-s"><code>is_deleted</code><span class="md-plain"> 字段来标记数据是否失效,而不是真的删除数据,这样即使误删也能恢复。</span></span></span></span></span></p>
<p class="md-end-block md-p"><span class="md-image md-img-loaded" data-src="https://pic.yupi.icu/1/1764310197462-61a58983-8274-4b2d-a55d-48a671013a56.png"><img src="https://pic.yupi.icu/1/1764310197462-61a58983-8274-4b2d-a55d-48a671013a56.png"></span></p>
<p class="md-end-block md-p"> </p>
<h3 class="md-end-block md-heading"><span class="md-plain">客户端操作</span></h3>
<p class="md-end-block md-p"><span class="md-plain">你很是兴奋:用可视化工具真方便啊,但是我怎么用代码操作数据库呢?</span></p>
<p class="md-end-block md-p"><span class="md-plain">鱼皮:主流编程语言都有操作数据库的 SDK,比如使用 Java 的 JDBC,需要先加载对应数据库的驱动、然后获取连接、编写 SQL 语句并执行、最后收集结果并关闭连接。</span></p>
<p class="md-end-block md-p"><span class="md-image md-img-loaded" data-src="https://pic.yupi.icu/1/1764310246424-47e63f98-cbf1-4e27-bbed-7799d344f28c.png"><img src="https://pic.yupi.icu/1/1764310246424-47e63f98-cbf1-4e27-bbed-7799d344f28c.png"></span></p>
<p class="md-end-block md-p"><span class="md-plain">你挠了挠头:我就查询 1 次数据库,都要写这么多代码么?而且我根本不会写 SQL 语句啊!</span></p>
<p class="md-end-block md-p"><span class="md-plain">鱼皮笑道:没关系,实际开发中我们会使用 <span class="md-pair-s "><strong>ORM 对象关系映射框架</strong><span class="md-plain">,可以把数据库的表映射成 Java 对象,像操作对象一样操作数据库。</span></span></span></p>
<p class="md-end-block md-p"><span class="md-image md-img-loaded" data-src="https://pic.yupi.icu/1/1764310264208-9825da1b-6d4c-48b6-9af1-2106fad98e1a.png"><img src="https://pic.yupi.icu/1/1764310264208-9825da1b-6d4c-48b6-9af1-2106fad98e1a.png"></span></p>
<p class="md-end-block md-p"><span class="md-plain">比如 Java 的 MyBatis 框架,可以让你用更简洁的方式执行 SQL:</span></p>
<pre class="md-fences md-end-block ty-contain-cm modeLoaded"><span><span class="cm-comment">// MyBatis 方式:只需要写 SQL,框架自动处理连接和结果映射<br><span><span class="cm-variable">Student <span class="cm-variable">student <span class="cm-operator">= <span class="cm-variable">studentMapper.<span class="cm-variable">selectByStudentNo(<span class="cm-number">2024001);<br><span><span class="cm-variable">System.<span class="cm-variable">out.<span class="cm-variable">println(<span class="cm-variable">student.<span class="cm-variable">getName());</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></pre>
<p class="md-end-block md-p"><span class="md-plain">还有它的增强版 MyBatis Plus 和 MyBatis Flex,提供了更多开箱即用的功能,连 SQL 都不用写!直接调用现成的方法,几行代码就能实现增删改查,告别 SQL Boy!</span></p>
<p class="md-end-block md-p"><span class="md-image md-img-loaded" data-src="https://pic.yupi.icu/1/1764310278329-40a2a58c-da5e-4bd0-83a9-6f63609b0813.png"><img src="https://pic.yupi.icu/1/1764310278329-40a2a58c-da5e-4bd0-83a9-6f63609b0813.png"></span></p>
<p class="md-end-block md-p"><span class="md-plain">你感叹道:这才是人写的代码啊!优雅,真是优雅~</span></p>
<p class="md-end-block md-p"><span class="md-plain">鱼皮提醒道:但是,框架不是万能的,有些复杂查询的 SQL 还要自己手写,不过现在有 AI 了,写个 SQL 还不是手拿把掐的?</span></p>
<p class="md-end-block md-p"><span class="md-plain">你:明白了,我这就用框架重写学生管理系统。</span></p>
<p class="md-end-block md-p"> </p>
<h2 class="md-end-block md-heading"><span class="md-plain">第三阶段:数据库特性</span></h2>
<h3 class="md-end-block md-heading"><span class="md-plain">索引</span></h3>
<p class="md-end-block md-p"><span class="md-plain">一个月后,你重写的学生管理系统正式上线,不仅得到了甲方的好评,而且很快火遍了全国高校。</span></p>
<p class="md-end-block md-p"><span class="md-plain">你内心暗爽:数据库也不过如此嘛~</span></p>
<p class="md-end-block md-p"><span class="md-image md-img-loaded" data-src="https://pic.yupi.icu/1/1764310319844-53beb52e-d201-4a39-a539-f00cf434ab41.jpeg"><img src="https://pic.yupi.icu/1/1764310319844-53beb52e-d201-4a39-a539-f00cf434ab41.jpeg"></span></p>
<p class="md-end-block md-p"><span class="md-plain">但你没想到,随着学生数据量的暴涨和表结构的扩展,你的数据库查询速度也越来越慢,光是查询某个班级的学生竟然都要等好几秒!</span></p>
<p class="md-end-block md-p"><span class="md-plain">你有些惊讶:我这 SQL 也不复杂啊,怎么查询这么慢?</span></p>
<p class="md-end-block md-p"><span class="md-plain">鱼皮:加个索引试试?</span></p>
<p class="md-end-block md-p"><span class="md-plain">你:索引?那是啥?</span></p>
<p class="md-end-block md-p"><span class="md-plain">鱼皮:索引就是数据库的目录。你现在查数据,数据库得一行一行全表扫描,数据量越大速度越慢。加了索引后,数据库可以通过索引快速定位到数据,就像通过书的目录快速翻到某一页。</span></p>
<p class="md-end-block md-p"><span class="md-image md-img-loaded" data-src="https://pic.yupi.icu/1/1764310360872-47b15a84-e541-4414-aa3b-e73c9cea3484.png"><img src="https://pic.yupi.icu/1/1764310360872-47b15a84-e541-4414-aa3b-e73c9cea3484.png"></span></p>
<p class="md-end-block md-p"><span class="md-plain">你恍然大悟:对啊,老师经常按班级查询学生,不妨给班级字段添加索引。</span></p>
<pre class="md-fences md-end-block ty-contain-cm modeLoaded"><span><span class="cm-keyword">CREATE <span class="cm-keyword">INDEX idx_class_id <span class="cm-keyword">ON student<span class="cm-bracket">(class_id<span class="cm-bracket">)<span class="cm-punctuation">;</span></span></span></span></span></span></span></pre>
<p class="md-end-block md-p"><span class="md-plain">添加索引后,你再次测试查询,竟然只要几十毫秒!</span></p>
<p class="md-end-block md-p"><span class="md-plain">你激动得跳了起来:索引太香了,我要给所有字段都加索引~</span></p>
<p class="md-end-block md-p"><span class="md-plain">鱼皮摆摆手:别,索引可不是越多越好!</span></p>
<p class="md-end-block md-p"><span class="md-plain">你愣住了:为啥?</span></p>
<p class="md-end-block md-p"><span class="md-plain">鱼皮:索引虽然能加快查询,但也有代价。</span></p>
<ul class="ul-list" data-mark="-">
<li class="md-list-item">
<p class="md-end-block md-p"><span class="md-plain">一方面会增加写入数据(增删改)的开销。因为每次写入数据,索引也要更新。</span></p>
</li>
<li class="md-list-item">
<p class="md-end-block md-p"><span class="md-plain">此外,索引本身也是数据,要占用更多的存储空间。</span></p>
</li>
</ul>
<p class="md-end-block md-p"><span class="md-image md-img-loaded" data-src="https://pic.yupi.icu/1/1764310402775-c97e3d03-2a39-41f2-9ef6-3e9be25bf9b2.png"><img src="https://pic.yupi.icu/1/1764310402775-c97e3d03-2a39-41f2-9ef6-3e9be25bf9b2.png"></span></p>
<p class="md-end-block md-p"><span class="md-plain">所以,要在经常用来查询、并且数据区分度高的字段上合理添加索引。比如班级 ID、学号这种字段适合加索引,但性别字段(只有男女两个值)就不适合。</span></p>
<p class="md-end-block md-p"><span class="md-image md-img-loaded" data-src="https://pic.yupi.icu/1/1764310425022-4cbd2cfe-a9ae-46b8-93a7-65e4e970e677.png"><img src="https://pic.yupi.icu/1/1764310425022-4cbd2cfe-a9ae-46b8-93a7-65e4e970e677.png"></span></p>
<p class="md-end-block md-p"> </p>
<h3 class="md-end-block md-heading"><span class="md-plain">事务</span></h3>
<p class="md-end-block md-p"><span class="md-plain">又过了几天,甲方又提新需求了。</span></p>
<p class="md-end-block md-p"><span class="md-plain">甲方:小阿巴,有老师反馈题目判错了,需要批量把所有学生的成绩都加 5 分。</span></p>
<p class="md-end-block md-p"><span class="md-plain">你信心满满:简单,不就是个批量更新操作么?</span></p>
<p class="md-end-block md-p"><span class="md-plain">你写了一段代码,循环更新所有学生的成绩。</span></p>
<p class="md-end-block md-p"><span class="md-image md-img-loaded" data-src="https://pic.yupi.icu/1/1764310445321-2de8813c-7b5b-43f6-bc43-a5331fe124c7.png"><img src="https://pic.yupi.icu/1/1764310445321-2de8813c-7b5b-43f6-bc43-a5331fe124c7.png"></span></p>
<p class="md-end-block md-p"><span class="md-plain">没想到,越自信 Bug 越多,功能刚刚上线,就收到了投诉:怎么有些学生的成绩改了,有些没改?</span></p>
<p class="md-end-block md-p"><span class="md-plain">你查看了下日志,发现前面学生的成绩更新成功了,但由于网络波动,导致后面的学生都没更新。</span></p>
<p class="md-end-block md-p"><span class="md-image md-img-loaded" data-src="https://pic.yupi.icu/1/1764310473289-ae87ff93-e897-4d2c-8000-420198eadaa6.png"><img src="https://pic.yupi.icu/1/1764310473289-ae87ff93-e897-4d2c-8000-420198eadaa6.png"></span></p>
<p class="md-end-block md-p"><span class="md-plain">你急坏了:咋办,这样就不公平了啊!</span></p>
<p class="md-end-block md-p"><span class="md-plain">鱼皮看了看你的代码:这是典型的数据一致性问题,你需要用 <span class="md-pair-s "><strong>事务</strong><span class="md-plain"> 来解决。</span></span></span></p>
<p class="md-end-block md-p"><span class="md-plain">你:啥是事务?</span></p>
<p class="md-end-block md-p"><span class="md-plain">鱼皮:事务就是把多个操作捆绑在一起,要么全部成功,要么全部失败。</span></p>
<p class="md-end-block md-p"><span class="md-image md-img-loaded" data-src="https://pic.yupi.icu/1/1764310530499-cc51d424-13d2-47ee-9b52-675a6b65b70e.png"><img src="https://pic.yupi.icu/1/1764310530499-cc51d424-13d2-47ee-9b52-675a6b65b70e.png"></span></p>
<p class="md-end-block md-p"><span class="md-plain">就像你给别人投币,你扣除硬币和对方增加硬币必须同时成功,不能让硬币凭空消失对吧?</span></p>
<p class="md-end-block md-p"><span class="md-plain">你:对对对,那批量改成绩也是,要么所有学生都加 5 分,要么都不加。</span></p>
<p class="md-end-block md-p"><span class="md-plain">鱼皮:没错,数据库事务有 4 个特性,简称 ACID:</span></p>
<ul class="ul-list" data-mark="-">
<li class="md-list-item">
<p class="md-end-block md-p"><span class="md-plain">原子性(<span class="md-pair-s "><strong>A</strong><span class="md-plain">tomicity):要么全做,要么全不做。</span></span></span></p>
</li>
<li class="md-list-item">
<p class="md-end-block md-p"><span class="md-plain">一致性(<span class="md-pair-s "><strong>C</strong><span class="md-plain">onsistency):数据从一个正确状态到另一个正确状态。比如转账时,A 扣钱和 B 加钱的总和不变。</span></span></span></p>
</li>
<li class="md-list-item">
<p class="md-end-block md-p"><span class="md-plain">隔离性(<span class="md-pair-s "><strong>I</strong><span class="md-plain">solation):多个事务互不干扰。</span></span></span></p>
</li>
<li class="md-list-item">
<p class="md-end-block md-p"><span class="md-plain">持久性(<span class="md-pair-s "><strong>D</strong><span class="md-plain">urability):事务完成后,数据永久保存。</span></span></span></p>
</li>
</ul>
<p class="md-end-block md-p"><span class="md-image md-img-loaded" data-src="https://pic.yupi.icu/1/1764310558430-85cce8e8-d082-43d6-ad16-dc576a6da21e.png"><img src="https://pic.yupi.icu/1/1764310558430-85cce8e8-d082-43d6-ad16-dc576a6da21e.png"></span></p>
<p class="md-end-block md-p"><span class="md-plain">你:那怎么使用事务呢?</span></p>
<p class="md-end-block md-p"><span class="md-plain">鱼皮:如果直接用原始的 JDBC,需要手动控制事务,比较麻烦。</span></p>
<p class="md-end-block md-p"><span class="md-plain">但如果在 Spring 框架中,只需要加一个 <span class="md-pair-s"><code>@Transactional</code><span class="md-plain"> 注解就搞定了:</span></span></span></p>
<p class="md-end-block md-p"><span class="md-image md-img-loaded" data-src="https://pic.yupi.icu/1/1764310596353-65723b65-b43e-4c45-91c2-f211eb8bc8bc.png"><img src="https://pic.yupi.icu/1/1764310596353-65723b65-b43e-4c45-91c2-f211eb8bc8bc.png"></span></p>
<p class="md-end-block md-p"><span class="md-plain">Spring 会自动帮你管理事务。如果中间任何一步出错,抛出了指定的异常,整个事务会自动回滚,将数据恢复到原来的状态,保证要么所有学生都加分成功,要么都不加。</span></p>
<p class="md-end-block md-p"><span class="md-image md-img-loaded" data-src="https://pic.yupi.icu/1/1764310625370-9ef7c2f5-56de-4505-b28a-27354f213cf7.png"><img src="https://pic.yupi.icu/1/1764310625370-9ef7c2f5-56de-4505-b28a-27354f213cf7.png"></span></p>
<p class="md-end-block md-p"><span class="md-plain">你:原来这么简单啊,我这就用事务重写代码!</span></p>
<p class="md-end-block md-p"> </p>
<h3 class="md-end-block md-heading"><span class="md-plain">其他</span></h3>
<p class="md-end-block md-p"><span class="md-plain">鱼皮:MySQL 还有一些其他特性,比如视图可以用来简化复杂查询、存储过程可以批量执行 SQL、触发器可以自动触发操作。</span></p>
<p class="md-end-block md-p"><span class="md-plain">1)视图:视图是一个虚拟表,把复杂查询封装起来重复使用。比如你经常要统计每个班级的平均成绩,每次都写一长串 SQL 太麻烦,可以创建一个视图,以后直接查视图就行。</span></p>
<p class="md-end-block md-p"><span class="md-plain">2)存储过程:可以批量执行 SQL。比如每天定时同步数据,写个存储过程,定时调用就行。</span></p>
<p class="md-end-block md-p"><span class="md-plain">3)触发器:可以自动触发操作。比如每次添加用户,自动生成一条操作日志,不用手动写代码。</span></p>
<p class="md-end-block md-p"><span class="md-image md-img-loaded" data-src="https://pic.yupi.icu/1/1764310647581-ae014154-750b-4506-be83-7a6514e284b3.png"><img src="https://pic.yupi.icu/1/1764310647581-ae014154-750b-4506-be83-7a6514e284b3.png"></span></p>
<p class="md-end-block md-p"><span class="md-plain">你感叹道:原来数据库还有这么多功能,我学不完了啊……</span></p>
<p class="md-end-block md-p"><span class="md-plain">鱼皮笑了:别担心,这些在实际开发中用得不多,先简单了解就好。</span></p>
<p class="md-end-block md-p"> </p>
<h2 class="md-end-block md-heading"><span class="md-plain">第四阶段:生产环境实践</span></h2>
<p class="md-end-block md-p"><span class="md-plain">几年后,你已经成为小有名气的 “学生管理系统大师”,还成立了自己的工作室。</span></p>
<p class="md-end-block md-p"><span class="md-plain">没事儿就对着新来的实习生阿坤吹牛皮:你阿巴哥我啊,精通数据库,索引、事务耍的贼溜儿~</span></p>
<p class="md-end-block md-p"><span class="md-image md-img-loaded" data-src="https://pic.yupi.icu/1/1764310683555-fdc45159-72d6-49d7-b1f4-a8a8dc143974.png"><img src="https://pic.yupi.icu/1/1764310683555-fdc45159-72d6-49d7-b1f4-a8a8dc143974.png"></span></p>
<p class="md-end-block md-p"><span class="md-plain">然而某天上午,学校的运维同学打来电话:阿巴阿巴,系统出问题了,所有操作都一直 <span class="md-pair-s "><strong>转圈、超时</strong><span class="md-plain">! 好像是数据库卡死了!</span></span></span></p>
<p class="md-end-block md-p"><span class="md-image md-img-loaded" data-src="https://pic.yupi.icu/1/1764310717983-197bf0cc-97ae-4015-9711-74e8330adf54.png"><img src="https://pic.yupi.icu/1/1764310717983-197bf0cc-97ae-4015-9711-74e8330adf54.png"></span></p>
<p class="md-end-block md-p"><span class="md-plain">你大惊:什么?!我都加索引了,还能卡死?</span></p>
<p class="md-end-block md-p"><span class="md-image md-img-loaded" data-src="https://pic.yupi.icu/1/1764310744549-8303df00-3dcd-46fb-8203-5a2d79f5f63a.jpeg"><img src="https://pic.yupi.icu/1/1764310744549-8303df00-3dcd-46fb-8203-5a2d79f5f63a.jpeg"></span></p>
<p class="md-end-block md-p"><span class="md-plain">emmm…… 对了,我想到了!</span></p>
<p class="md-end-block md-p"><span class="md-plain">赶紧重启数据库,重启解决所有问题!嘿嘿嘿哈哈哈哈~</span></p>
<p class="md-end-block md-p"><span class="md-image md-img-loaded" data-src="https://pic.yupi.icu/1/1764310826542-2912e80e-e472-45e5-8a68-249918ee0e63.png"><img src="https://pic.yupi.icu/1/1764310826542-2912e80e-e472-45e5-8a68-249918ee0e63.png"></span></p>
<p class="md-end-block md-p"><span class="md-plain">结果重启没多久,数据库又卡死了!</span></p>
<p class="md-end-block md-p"><span class="md-plain">你彻底懵了:呜呜呜,怎么办啊!</span></p>
<p class="md-end-block md-p"><span class="md-plain">这时,你身旁的阿坤突然鸡叫起来:我来!</span></p>
<p class="md-end-block md-p"><span class="md-image md-img-loaded" data-src="https://pic.yupi.icu/1/1764310850182-ebbeeea7-8792-4e15-86c6-a7636b810a89.png"><img src="https://pic.yupi.icu/1/1764310850182-ebbeeea7-8792-4e15-86c6-a7636b810a89.png"></span></p>
<p class="md-end-block md-p"> </p>
<h3 class="md-end-block md-heading"><span class="md-plain">为什么系统会崩溃?</span></h3>
<p class="md-end-block md-p"><span class="md-plain">阿坤:我们先看看为什么系统会崩溃?</span></p>
<p class="md-end-block md-p"><span class="md-plain">开启 MySQL 的慢查询日志功能,有两种方式。</span></p>
<p class="md-end-block md-p"><span class="md-plain">1)通过 SQL 命令(临时开启)</span></p>
<pre class="md-fences md-end-block ty-contain-cm modeLoaded"><span><span class="cm-comment"># 开启慢查询日志功能<br><span>SET GLOBAL slow_query_log <span class="cm-operator">= <span class="cm-number">1;<br><span><span><br><span><span class="cm-comment"># 设置慢查询阈值(超过几秒算是慢查询)<br><span>SET GLOBAL long_query_time <span class="cm-operator">= <span class="cm-number">5;<br><span><span><br><span><span class="cm-comment"># 修改日志文件位置(可选)<br><span>SET GLOBAL slow_query_log_file <span class="cm-operator">= <span class="cm-string">'/path/to/slow.log';</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></pre>
<p class="md-end-block md-p"><span class="md-plain">2)修改配置文件(永久生效)</span></p>
<pre class="md-fences md-end-block ty-contain-cm modeLoaded"><span><span class="cm-comment"># 在 部分设置参数<br><span>slow_query_log <span class="cm-operator">= <span class="cm-number">1<br><span>long_query_time <span class="cm-operator">= <span class="cm-number">5<br><span>slow_query_log_file <span class="cm-operator">= /path/to/slow.log</span></span></span></span></span></span></span></span></span></span></pre>
<p class="md-end-block md-p"> </p>
<p class="md-end-block md-p"><span class="md-plain">你看,有些 SQL 语句执行了几十秒!</span></p>
<p class="md-end-block md-p"><span class="md-image md-img-loaded" data-src="https://pic.yupi.icu/1/1764310892126-d474b9f4-f844-4cdb-9985-c20f8e22b515.png"><img src="https://pic.yupi.icu/1/1764310892126-d474b9f4-f844-4cdb-9985-c20f8e22b515.png"></span></p>
<p class="md-end-block md-p"><span class="md-plain">使用 Explain 命令分析下这些查询,原来没有正确使用索引,导致了全表扫描,把数据库拖垮了。</span></p>
<p class="md-end-block md-p"><span class="md-image md-img-loaded" data-src="https://pic.yupi.icu/1/1764310914647-20ff20d8-0a4e-45a1-b865-cea5279f374a.png"><img src="https://pic.yupi.icu/1/1764310914647-20ff20d8-0a4e-45a1-b865-cea5279f374a.png"></span></p>
<p class="md-end-block md-p"><span class="md-plain">这些慢查询就是罪魁祸首,它们会 <span class="md-pair-s "><strong>长时间霸占数据库连接和 CPU 资源</strong><span class="md-plain">。当大量用户同时执行慢查询,数据库连接池很快被耗尽,新的请求因为无法获取连接、全部阻塞,导致数据库 “卡死”。</span></span></span></p>
<p class="md-end-block md-p"><span class="md-image md-img-loaded" data-src="https://pic.yupi.icu/1/1764310961293-051c2682-afa8-4f9a-91e3-40654975dcce.png"><img src="https://pic.yupi.icu/1/1764310961293-051c2682-afa8-4f9a-91e3-40654975dcce.png"></span></p>
<p class="md-end-block md-p"><span class="md-plain">你惭愧地低下头:我知道了,生产环境一定要开启慢查询日志,及时发现慢 SQL 并优化。</span></p>
<p class="md-end-block md-p"> </p>
<h3 class="md-end-block md-heading"><span class="md-plain">数据丢失了怎么办?</span></h3>
<p class="md-end-block md-p"><span class="md-plain">屋漏偏逢连夜雨,你很快又收到了投诉,说是有的学生数据丢失了!</span></p>
<p class="md-end-block md-p"><span class="md-plain">你很是疑惑:MySQL 不是有日志(Redo Log 和 Binlog)来保证数据持久性吗?怎么会丢数据呢?</span></p>
<p class="md-end-block md-p"><span class="md-image md-img-loaded" data-src="https://pic.yupi.icu/1/1764310979421-c3e49a4c-8926-47e4-be7b-5e0e042378d2.png"><img src="https://pic.yupi.icu/1/1764310979421-c3e49a4c-8926-47e4-be7b-5e0e042378d2.png"></span></p>
<p class="md-end-block md-p"><span class="md-plain">经过排查,原来是服务器的硬盘被一个学生不小心踹坏了!</span></p>
<p class="md-end-block md-p"><span class="md-plain">你难受得像持矢了一样:真是人在家中坐,Bug 天上来。</span></p>
<p class="md-end-block md-p"><span class="md-image md-img-loaded" data-src="https://pic.yupi.icu/1/1764311236080-bf743082-d16f-4b91-b147-58a4232e3f13.png"><img src="https://pic.yupi.icu/1/1764311236080-bf743082-d16f-4b91-b147-58a4232e3f13.png"></span></p>
<p class="md-end-block md-p"><span class="md-plain">唉,我怎么把数据找回来啊?</span></p>
<p class="md-end-block md-p"><span class="md-plain">阿坤:别怕,幸好鱼皮哥之前设置了备份。一方面定期做 <span class="md-pair-s "><strong>全量备份</strong><span class="md-plain">,比如利用 <span class="md-pair-s"><code>mysqldump</code><span class="md-plain"> 工具每天凌晨备份一次并发送到其他服务器上;再配合 <span class="md-pair-s "><strong>增量备份</strong><span class="md-plain">,利用 Binlog(二进制日志)记录每次的数据修改操作,这样即使数据库崩了,也能恢复到最近的状态。</span></span></span></span></span></span></span></p>
<p class="md-end-block md-p"><span class="md-image md-img-loaded" data-src="https://pic.yupi.icu/1/1764311252024-daf1328f-4642-45e7-be68-2a9f4eb1dd2a.png"><img src="https://pic.yupi.icu/1/1764311252024-daf1328f-4642-45e7-be68-2a9f4eb1dd2a.png"></span></p>
<p class="md-end-block md-p"> </p>
<h3 class="md-end-block md-heading"><span class="md-plain">怎么保证系统不会再崩?</span></h3>
<p class="md-end-block md-p"><span class="md-plain">你松了一口气:那怎么保证数据库不会再宕机呢?</span></p>
<p class="md-end-block md-p"><span class="md-plain">阿坤:可以搭建 MySQL 高可用集群,典型的是 <span class="md-pair-s "><strong>一主多从</strong><span class="md-plain"> 架构。</span></span></span></p>
<p class="md-end-block md-p"><span class="md-plain">主库(Master)专门负责写操作(增删改),并通过 Binlog 记录每一次数据变更操作。</span></p>
<p class="md-end-block md-p"><span class="md-plain">从库(Slave) 拉取主库的 Binlog 到本地文件中,然后回放数据变更操作,实现数据同步。我们可以利用从库来承担绝大部分的读操作,这叫 <span class="md-pair-s "><strong>读写分离</strong><span class="md-plain">,能大大提升并发能力。</span></span></span></p>
<p class="md-end-block md-p"><span class="md-image md-img-loaded" data-src="https://pic.yupi.icu/1/1764311317365-cdf9a876-7b61-40b0-a518-896f95c86d0c.png"><img src="https://pic.yupi.icu/1/1764311317365-cdf9a876-7b61-40b0-a518-896f95c86d0c.png"></span></p>
<p class="md-end-block md-p"><span class="md-plain">当主库出现故障时,利用 <span class="md-pair-s "><strong>MHA</strong><span class="md-plain"> 等工具,自动将一个从库提升为新的主库,并调整其他从库的指向,实现故障的自动切换。</span></span></span></p>
<p class="md-end-block md-p"><span class="md-image md-img-loaded" data-src="https://pic.yupi.icu/1/1764311332185-650329db-d035-4104-b48f-d5182676423b.png"><img src="https://pic.yupi.icu/1/1764311332185-650329db-d035-4104-b48f-d5182676423b.png"></span></p>
<p class="md-end-block md-p"> </p>
<h3 class="md-end-block md-heading"><span class="md-plain">数据量大了怎么办?</span></h3>
<p class="md-end-block md-p"><span class="md-plain">你很是惊讶:之前完全没听说过这些啊……</span></p>
<p class="md-end-block md-p"><span class="md-plain">阿坤用看流浪狗的眼神看了你一眼:阿巴哥哥,如果数据量特别大,一个库存不下怎么办?</span></p>
<p class="md-end-block md-p"><span class="md-plain">你哑口无言:阿巴阿巴……</span></p>
<p class="md-end-block md-p"><span class="md-plain">阿坤笑了:当然是 <span class="md-pair-s "><strong>分库分表</strong><span class="md-plain"> 啦!比如</span></span></span></p>
<p class="md-end-block md-p"><span class="md-plain">1)水平拆分:把同一张表的数据分散到多个表或多个库中。比如根据学生 ID 的尾号,奇数的存到表 1,偶数的存到表 2。</span></p>
<p class="md-end-block md-p"><span class="md-image md-img-loaded" data-src="https://pic.yupi.icu/1/1764311483089-c63a6731-3a59-499d-b38d-6a31d380349c.png"><img src="https://pic.yupi.icu/1/1764311483089-c63a6731-3a59-499d-b38d-6a31d380349c.png"></span></p>
<p class="md-end-block md-p"><span class="md-plain">2)垂直拆分:按业务功能来拆分库,比如把学生基本信息、成绩信息、选课信息分别存到不同的库中。</span></p>
<p class="md-end-block md-p"><span class="md-image md-img-loaded" data-src="https://pic.yupi.icu/1/1764311503733-d741ff0e-8741-4423-aeaf-71706f29a114.png"><img src="https://pic.yupi.icu/1/1764311503733-d741ff0e-8741-4423-aeaf-71706f29a114.png"></span></p>
<p class="md-end-block md-p"><span class="md-plain">你彻底服了:妙啊,这样就能存储海量数据了!</span></p>
<p class="md-end-block md-p"> </p>
<h3 class="md-end-block md-heading"><span class="md-plain">其他实践</span></h3>
<p class="md-end-block md-p"><span class="md-plain">这时鱼皮走过来拍了拍阿坤的肩膀:小伙子年轻有为啊!</span></p>
<p class="md-end-block md-p"><span class="md-plain">小阿巴,MySQL 生产环境实践的知识点还有很多。比如:</span></p>
<p class="md-end-block md-p"><span class="md-plain">1)权限管理:不要所有人都用 root 账号,风险太大,要给不同的人分配不同的权限。</span></p>
<p class="md-end-block md-p"><span class="md-plain">2)云数据库服务:提供了现成的 MySQL 集群架构、监控系统、自动备份、数据迁移等,比自己运维省心多了。</span></p>
<p class="md-end-block md-p"><span class="md-image md-img-loaded" data-src="https://pic.yupi.icu/1/1764311597040-6d3d17f4-aafc-41c5-8acc-24eee7dadd39.png"><img src="https://pic.yupi.icu/1/1764311597040-6d3d17f4-aafc-41c5-8acc-24eee7dadd39.png"></span></p>
<p class="md-end-block md-p"><span class="md-plain">3)调优技巧:硬件优化、数据库配置优化、库表设计优化、SQL 优化、连接池优化等等。</span></p>
<p class="md-end-block md-p"><span class="md-plain">4)常见问题:还有死锁排查、大表的在线变更、数据迁移、主从延迟处理等等,遇到了再去解决。</span></p>
<p class="md-end-block md-p"><span class="md-plain">你羞愧地抬不起头:我以为自己已经掌握了数据库,原来只是学了个皮毛……</span></p>
<p class="md-end-block md-p"><span class="md-image md-img-loaded" data-src="https://pic.yupi.icu/1/1764311624798-20631444-4d6d-405d-892a-b1f1e6e897cb.jpeg"><img src="https://pic.yupi.icu/1/1764311624798-20631444-4d6d-405d-892a-b1f1e6e897cb.jpeg"></span></p>
<p class="md-end-block md-p"> </p>
<h2 class="md-end-block md-heading"><span class="md-plain">第五阶段:深入底层原理</span></h2>
<p class="md-end-block md-p"><span class="md-plain">于是,你主动找到阿坤:我想深入学习 MySQL,不能只停留在会用的层面,请问怎么学习底层原理啊?</span></p>
<p class="md-end-block md-p"><span class="md-plain">阿坤有些惊讶:咦?你不 <span class="md-meta-i-cmd-link"><span class="md-plain">背八股文</span><span class="md-plain"> 的么?刷刷题就好了呀!</span></span></span></p>
<p class="md-end-block md-p"><span class="md-plain">你震惊了:现在的实习生,竟然恐怖如斯!</span></p>
<p class="md-end-block md-p"><span class="md-image md-img-loaded" data-src="https://pic.yupi.icu/1/1764311871359-426e60a8-cf09-4dc5-996b-f9d2e9a85ae6.png"><img src="https://pic.yupi.icu/1/1764311871359-426e60a8-cf09-4dc5-996b-f9d2e9a85ae6.png"></span></p>
<p class="md-end-block md-p"> </p>
<p class="md-end-block md-p"><span class="md-plain">鱼皮:阿坤你别逗他了,其实我们可以带着问题学习。比如 <span class="md-pair-s "><strong>MySQL 是如何实现高效查询的</strong><span class="md-plain"> ?</span></span></span></p>
<p class="md-end-block md-p"><span class="md-plain">你想了想:加索引?</span></p>
<p class="md-end-block md-p"><span class="md-plain">鱼皮:对,但这只是使用层面。底层实现有很多技术,比如高效的存储引擎(InnoDB)、优秀的索引结构(B+ 树)、缓冲池机制、查询优化器等等。</span></p>
<p class="md-end-block md-p"><span class="md-image md-img-loaded" data-src="https://pic.yupi.icu/1/1764311903957-4c27e366-54e5-4075-8fd8-4e8cf39eb3d3.png"><img src="https://pic.yupi.icu/1/1764311903957-4c27e366-54e5-4075-8fd8-4e8cf39eb3d3.png"></span></p>
<p class="md-end-block md-p"><span class="md-plain">比如我考考你,下面两个 SQL 语句哪个执行更快?</span></p>
<pre class="md-fences md-end-block ty-contain-cm modeLoaded"><span><span class="cm-comment"># SQL 1: 使用 OR<br><span><span class="cm-keyword">SELECT <span class="cm-operator">* <span class="cm-keyword">FROM student <span class="cm-keyword">WHERE class_id <span class="cm-operator">= <span class="cm-number">1 <span class="cm-keyword">OR class_id <span class="cm-operator">= <span class="cm-number">2<span class="cm-punctuation">;<br><span><span><br><span><span class="cm-comment"># SQL 2: 使用 IN<br><span><span class="cm-keyword">SELECT <span class="cm-operator">* <span class="cm-keyword">FROM student <span class="cm-keyword">WHERE class_id <span class="cm-keyword">IN <span class="cm-bracket">(<span class="cm-number">1<span class="cm-punctuation">, <span class="cm-number">2<span class="cm-bracket">)<span class="cm-punctuation">;</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></pre>
<p class="md-end-block md-p"><span class="md-plain">你:额…… 第 2 个?因为它更简短。</span></p>
<p class="md-end-block md-p"><span class="md-plain">鱼皮:哼哼,答案是 <span class="md-pair-s "><strong>几乎一样快</strong><span class="md-plain">!因为 MySQL 的查询优化器非常智能,它会分析语句、将它们处理成相同的逻辑结构,再去执行。</span></span></span></p>
<p class="md-end-block md-p"><span class="md-plain">这就是 MySQL 能高效查询的原因之一,带着这些问题去阅读相关文章,或者直接像阿坤说的刷一刷 MySQL 面试题,就能快速学会很多核心知识点。</span></p>
<p class="md-end-block md-p"><span class="md-image md-img-loaded" data-src="https://i0.hdslb.com/bfs/new_dyn/53707edddfe13a7ee4bc48105aed384112890453.png"><img src="https://i0.hdslb.com/bfs/new_dyn/53707edddfe13a7ee4bc48105aed384112890453.png"></span></p>
<p class="md-end-block md-p"><span class="md-plain">如果想系统学习,可以看看《MySQL 是怎样运行的》、《高性能 MySQL》这几本书。</span></p>
<p class="md-end-block md-p"><span class="md-image md-img-loaded" data-src="https://i0.hdslb.com/bfs/new_dyn/26d185269babadb1665772f2f6f6947e12890453.png"><img src="https://i0.hdslb.com/bfs/new_dyn/26d185269babadb1665772f2f6f6947e12890453.png"></span></p>
<p class="md-end-block md-p"><span class="md-plain">要记住,学习底层原理不只是为了应付面试,而是为了更好地使用 MySQL,遇到问题时能够快速定位和解决。</span></p>
<p class="md-end-block md-p"><span class="md-plain">你:好的,我这就去学!</span></p>
<p class="md-end-block md-p"> </p>
<h2 class="md-end-block md-heading"><span class="md-plain">结尾</span></h2>
<p class="md-end-block md-p"><span class="md-plain">若干年后,你已经成为了大厂的数据库专家。不仅能熟练设计库表、优化性能,搭个 MySQL 集群也是手拿把掐的。</span></p>
<p class="md-end-block md-p"><span class="md-plain">!<span class="md-image md-img-loaded" data-src="https://i0.hdslb.com/bfs/new_dyn/ab030fe1ebb62db11e00e1a6ab99181c12890453.png"><img src="https://i0.hdslb.com/bfs/new_dyn/ab030fe1ebb62db11e00e1a6ab99181c12890453.png"></span></span></p>
<p class="md-end-block md-p"><span class="md-plain">你也像鱼皮当时一样,耐心地给新人分享学习数据库的经验:数据库是实战型技术,一定要多动手实践。</span></p>
<p class="md-end-block md-p"><span class="md-image md-img-loaded" data-src="https://i0.hdslb.com/bfs/new_dyn/2ecde8f546513fdbd44ba0c193be432812890453.png"><img src="https://i0.hdslb.com/bfs/new_dyn/2ecde8f546513fdbd44ba0c193be432812890453.png"></span></p>
<p class="md-end-block md-p md-focus"><span class="md-plain md-expand">再次遇到鱼皮是在一条昏暗的小巷,此时的他年过 35,灰头土脸。你什么都没说,只是给他点了个赞,不打扰,是你的温柔。</span></p>
<p class="md-end-block md-p"><span class="md-image md-img-loaded" data-src="https://i0.hdslb.com/bfs/new_dyn/acd2004a05376aebee79b2f8e076f98912890453.png"><img src="https://i0.hdslb.com/bfs/new_dyn/acd2004a05376aebee79b2f8e076f98912890453.png"></span></p>
<p class="md-end-block md-p"><span class="md-plain">更详细的 <span class="md-meta-i-cmd-link"><span class="md-plain">MySQL 数据库学习路线</span><span class="md-plain">,可以在编程导航免费阅读哦。</span></span></span></p>
<p class="md-end-block md-p"> </p>
<h2 class="md-end-block md-heading"><span class="md-plain">更多编程学习资源</span></h2>
<ul class="ul-list" data-mark="-">
<li class="md-list-item">
<p class="md-end-block md-p"><span class="md-meta-i-cmd-link"><span class="md-plain">Java前端程序员必做项目实战教程+毕设网站</span></span></p>
</li>
<li class="md-list-item">
<p class="md-end-block md-p"><span class="md-meta-i-cmd-link"><span class="md-plain">程序员免费编程学习交流社区(自学必备)</span></span></p>
</li>
<li class="md-list-item">
<p class="md-end-block md-p"><span class="md-meta-i-cmd-link"><span class="md-plain">程序员保姆级求职写简历指南(找工作必备)</span></span></p>
</li>
<li class="md-list-item">
<p class="md-end-block md-p"><span class="md-meta-i-cmd-link"><span class="md-plain">程序员免费面试刷题网站工具(找工作必备)</span></span></p>
</li>
<li class="md-list-item">
<p class="md-end-block md-p"><span class="md-meta-i-cmd-link"><span class="md-plain">最新Java零基础入门学习路线 + Java教程</span></span></p>
</li>
<li class="md-list-item">
<p class="md-end-block md-p"><span class="md-meta-i-cmd-link"><span class="md-plain">最新Python零基础入门学习路线 + Python教程</span></span></p>
</li>
<li class="md-list-item">
<p class="md-end-block md-p"><span class="md-meta-i-cmd-link"><span class="md-plain">最新前端零基础入门学习路线 + 前端教程</span></span></p>
</li>
<li class="md-list-item">
<p class="md-end-block md-p"><span class="md-meta-i-cmd-link"><span class="md-plain">最新数据结构和算法零基础入门学习路线 + 算法教程</span></span></p>
</li>
<li class="md-list-item">
<p class="md-end-block md-p"><span class="md-meta-i-cmd-link"><span class="md-plain">最新C++零基础入门学习路线、C++教程</span></span></p>
</li>
<li class="md-list-item">
<p class="md-end-block md-p"><span class="md-meta-i-cmd-link"><span class="md-plain">最新数据库零基础入门学习路线 + 数据库教程</span></span></p>
</li>
<li class="md-list-item">
<p class="md-end-block md-p"><span class="md-meta-i-cmd-link"><span class="md-plain">最新Redis零基础入门学习路线 + Redis教程</span></span></p>
</li>
<li class="md-list-item">
<p class="md-end-block md-p"><span class="md-meta-i-cmd-link"><span class="md-plain">最新计算机基础入门学习路线 + 计算机基础教程</span></span></p>
</li>
<li class="md-list-item">
<p class="md-end-block md-p"><span class="md-meta-i-cmd-link"><span class="md-plain">最新小程序入门学习路线 + 小程序开发教程</span></span></p>
</li>
<li class="md-list-item">
<p class="md-end-block md-p"><span class="md-meta-i-cmd-link"><span class="md-plain">最新SQL零基础入门学习路线 + SQL教程</span></span></p>
</li>
<li class="md-list-item">
<p class="md-end-block md-p"><span class="md-meta-i-cmd-link"><span class="md-plain">最新Linux零基础入门学习路线 + Linux教程</span></span></p>
</li>
<li class="md-list-item">
<p class="md-end-block md-p"><span class="md-meta-i-cmd-link"><span class="md-plain">最新Git/GitHub零基础入门学习路线 + Git教程</span></span></p>
</li>
<li class="md-list-item">
<p class="md-end-block md-p"><span class="md-meta-i-cmd-link"><span class="md-plain">最新操作系统零基础入门学习路线 + 操作系统教程</span></span></p>
</li>
<li class="md-list-item">
<p class="md-end-block md-p"><span class="md-meta-i-cmd-link"><span class="md-plain">最新计算机网络零基础入门学习路线 + 计算机网络教程</span></span></p>
</li>
<li class="md-list-item">
<p class="md-end-block md-p"><span class="md-meta-i-cmd-link"><span class="md-plain">最新设计模式零基础入门学习路线 + 设计模式教程</span></span></p>
</li>
<li class="md-list-item">
<p class="md-end-block md-p"><span class="md-meta-i-c md-link"><span class="md-plain">最新软件工程零基础入门学习路线 + 软件工程教程</span></span></p>
</li>
</ul><br><br>
来源:https://www.cnblogs.com/yupi/p/19296770
頁:
[1]