1. 这节笔记在讲什么
上午的课排到第34节,正好讲数据库的“地基工程”--创建数据库和跑通各类SQL。这节内容不复杂,但信息密度很高。老实说,很多人学了几个月MySQL,建库建表都靠Navicat点鼠标,让他打开命令行敲CREATE DATABASE反而卡壳。这节笔记想解决的,就是这种“会用工具、不懂本质”的尴尬。
适合三类人看:刚入门想把SQL基础打牢的新手、用图形界面工具太久想补命令行基本功的人、以及准备面试或者做技术复盘的老开发。这节内容把从连接到建库、从建表到增删改查的完整链路过了一遍,每一类SQL都配了实操演示和易错点,照着敲一遍比空看十遍都管用。
整节笔记的时间跨度是上午三节课连排,前半段讲建库和管理库,后半段重点过SQL的四大分类——DDL、DML、DQL、DCL。每个分类都拆了语法结构、执行顺序和常见报错。下面按课堂推进的顺序,把核心知识点和实操细节整理出来,附带一些那个环境下踩过的坑。
2. 建库之前,先把连接链路理清楚
2.1 连接MySQL的两种姿势
要创建数据库,第一步当然是先连上MySQL服务。课上演示了两种连接方式,各有各的适用场景。
第一种是命令行直连。打开终端,输入:
mysql -uroot -p回车后输入密码就进入了MySQL的交互终端。如果MySQL装在远程服务器上,需要指定IP和端口:
mysql -h192.168.1.100 -P3306 -uroot -p注意-h后面是主机地址,-P是大写P指定端口,-u后面是用户名,-p表示需要输入密码。这里有坑,-p和密码之间不能有空格,如果写成-p 123456,MySQL会把123456当成数据库名去连接,直接报错。
第二种就是用图形化工具,Navicat、DBeaver、DataGrip都行。这种方式适合日常管理,看数据、导数据、跑查询都方便。但建库建表这种基础操作,我反而建议多用命令行敲几遍。原因很简单,图形化工具把语法都给你包好了,点几下就完事,你根本记不住SQL长什么样。等到线上环境没有图形化工具,只有终端的时候,平时敲过的命令就是你唯一能依赖的东西。
2.2 连接后必做的三件事
连上MySQL之后,别急着建库,先花一分钟确认环境状态。
第一件事,看版本。执行SELECT VERSION();确认当前MySQL版本。这节实操环境中装的是MySQL 8.0,因为8.0和5.7在不少语法细节上有差异,后续很多操作都跟版本相关。
第二件事,看当前有哪些数据库。执行SHOW DATABASES;,默认会有information_schema、mysql、performance_schema、sys这四个系统库,它们是MySQL自己维护的,平时别去动它们。
第三件事,确认字符集。执行:
SHOW VARIABLES LIKE 'character_set%';这一步很多人会跳过,但实际非常重要。如果服务器默认字符集不是utf8mb4,建库的时候没指定字符集的话,后面存emoji或者生僻字就会直接报错。课上这节环境默认就是utf8mb4,网上教学环境经常是latin1,差别非常大。字符集问题后面单独讲,先记住建库时显式指定是最稳妥的做法。
提示:连接后先看版本和字符集,这是排查一切诡异问题的起点。不少坑都是因为版本差异或者字符集不一致引起的,先确认这两个基础信息能省掉大量排查时间。
3. 创建数据库,核心细节都在这
3.1 标准语法和参数选择
创建数据库的标准语法是这样的:
CREATE DATABASE [IF NOT EXISTS] 数据库名 [CHARACTER SET 字符集名] [COLLATE 排序规则];方括号里的内容都是可选项,但实际建库时我建议都写上。
数据库名有一套命名规则要记牢:首字母必须是字母或者下划线,不能是数字开头;只能使用字母、数字、下划线、$符号,不能有空格和中划线;长度不能超过64个字符;不能用MySQL的关键字做数据库名,比如create、select这种词都不能直接用。如果非要用,必须用反引号包裹,但这是自找麻烦,不推荐。
IF NOT EXISTS这个选项,字面意思是“如果不存在才创建”。加上它之后,如果要建的数据库已经存在,MySQL不会报错,只是给一个警告提示。不加的话,重复创建同名数据库会直接报错ERROR 1007 (HY000): Can't create database 'xxx'; database exists。在实际操作中,脚本里最好都加上这个判断,避免重复执行时报错中断。
字符集这块是重点。MySQL 8.0默认字符集是utf8mb4,它才是真正的完整UTF-8,支持四字节的emoji字符。老版本MySQL里的utf8其实是个坑,它最多只能存三字节,遇到emoji就存不进去了。所以现在建库统一用utf8mb4,别用utf8。
排序规则和字符集配套使用。utf8mb4对应的排序规则,最常用的是utf8mb4_0900_ai_ci(MySQL 8.0默认)、utf8mb4_general_ci、utf8mb4_unicode_ci。其中_ci结尾表示大小写不敏感,_bin结尾表示按二进制比较,大小写敏感。
建库时完整写法示例:
CREATE DATABASE IF NOT EXISTS school_db CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci;字符集管的是“存什么”,排序规则管的是“怎么比”。比如排序规则用utf8mb4_bin的话,SELECT 'a' = 'A';返回的是0,说明大小写不同;用utf8mb4_0900_ai_ci的话返回1,说明忽略大小写。这个区别在做查询去重、排序、唯一索引的时候会产生看得见的影响。
3.2 建库之后怎么验证和管理
建完库不要直接跑,先确认一下建出来的库对不对。执行SHOW DATABASES;能看到所有数据库列表,确认新库在里面。再执行:
SHOW CREATE DATABASE school_db;这条命令能看到这个库完整的创建语句,包括字符集、排序规则这些属性。如果发现字符集不对,比如建库时没指定导致默认成了latin1,不需要删库重建,可以直接修改:
ALTER DATABASE school_db CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci;注意这是对数据库级别的修改,只能影响之后新建的表和表里新加的字段,已经建好的表如果之前指定了别的字符集,不会跟着变。
管理数据库还有两个常用操作。一个是切换当前库:
USE school_db;执行之后,命令行提示符会变成mysql>前面带上数据库名的格式,说明当前操作的就是这个库。另一个是删库:
DROP DATABASE school_db;这条命令要极其谨慎。MySQL没有回收站,没有确认提示,执行完数据库连同里面所有表、所有数据、所有存储过程、所有触发器瞬间全部没了。课上反复强调的一句话是:任何时候,生产环境的DROP DATABASE必须先备份,再确认,最后才执行。还有DROP DATABASE IF EXISTS school_db;这种语法,在脚本里用来做环境重置很常见,但同样要确认自己不是在对着生产库操作。
注意:执行
USE切换库之后,当前会话的所有操作都基于这个库。如果忘了切换,又没在表名前加库名前缀,MySQL会报ERROR 1046 (3D000): No database selected,这是新手最常见报错之一。
3.3 建表也顺手过了
笔记里建库之后紧接着就建了一张students表,演示了完整的建表语法:
CREATE TABLE IF NOT EXISTS students ( id INT UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '主键ID', name VARCHAR(50) NOT NULL COMMENT '姓名', gender CHAR(1) DEFAULT '男' COMMENT '性别', birth_date DATE COMMENT '出生日期', phone VARCHAR(20) UNIQUE COMMENT '手机号', created_at DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', PRIMARY KEY (id), KEY idx_name (name) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='学生表';这里有几个点值得细说。
INT UNSIGNED表示无符号整数,取值范围翻倍,从负数和正数的对称区间变成只有非负数,ID不可能为负,所以用UNSIGNED更合适。AUTO_INCREMENT表示自增列,让数据库自己维护一个递增的ID,不用手动赋值。每张表只能有一个自增列,而且这个列必须被索引,通常直接设为主键。
VARCHAR(50)括号里的数字是能存储的字符数,不是字节数。在utf8mb4字符集下,一个汉字算一个字符,所以VARCHAR(50)可以存50个汉字。这个跟CHAR不一样,CHAR是定长存储,VARCHAR是变长存储,前者适合存储长度基本固定的数据,比如性别、状态码;后者适合长度不固定的,比如名字、地址。
DEFAULT CURRENT_TIMESTAMP让created_at字段在插入新记录时自动填入当前时间,不需要在INSERT语句里手动写,这是非常实用的设计习惯。另外注意表名和字段名都加了反引号,这是为了防关键字冲突,虽然students和name都不是关键字,课程里说的是养成习惯,字段名、表名都加上反引号最保险。
ENGINE=InnoDB指定存储引擎。MySQL 8.0里默认就是InnoDB,不写也没问题,但显式写出来能让读SQL的人一眼看到引擎类型。InnoDB支持事务、支持外键、支持行级锁,是绝大多数场景的默认选择。闲鱼上面那些用MyISAM的老库,早该迁移了。
后面每个字段都加了COMMENT,表的最后也加了COMMENT,这是给表结构写文档。团队协作的时候,别人看你的表结构不用去翻需求文档,直接看注释就懂了。这个习惯非常值得养成。
4. 运行各类SQL,重点难点逐个过
4.1 SQL语言的四个家族
SQL全称Structured Query Language,结构化查询语言,它的命令可以按功能分成四类,这个分类特别重要,因为后续所有SQL学习都建立在它上面。
第一类是DDL,Data Definition Language,数据定义语言。负责定义、修改、删除数据库对象(库、表、索引、视图等)。关键词是CREATE、ALTER、DROP、TRUNCATE。这类语句操作完会自动提交事务,不能回滚,所以执行要格外小心。
第二类是DML,Data Manipulation Language,数据操纵语言。负责对表里的数据做增删改。关键词是INSERT、UPDATE、DELETE、SELECT(也有人说SELECT单独算DQL)。DML操作是事务性的,在InnoDB引擎下,可以配合BEGIN、COMMIT、ROLLBACK实现回滚。
第三类是DQL,Data Query Language,数据查询语言。专门负责查询,核心就是SELECT语句,后面接的WHERE、GROUP BY、ORDER BY、LIMIT这些子句都属于DQL的范畴。实际开发中,SQL写得最多的就是SELECT,性能优化主要也是针对这类语句做分析。
第四类是DCL,Data Control Language,数据控制语言。负责权限管理,关键词是GRANT、REVOKE,以及管理事务的COMMIT、ROLLBACK。这类语句在日常开发中很少直接用,主要是DBA在用。
把SQL按这几个家族分开理解,再去记命令就很有条理。哪类操作负责什么、能不能回滚、执行后果是什么,先分清楚再动手。
4.2 DDL实操:改表结构是高频操作
建完表之后,最常用的DDL是ALTER TABLE。课上进行了一个典型的操作演示,给students表新增一个字段并设置默认值:
ALTER TABLE students ADD COLUMN status TINYINT NOT NULL DEFAULT 1 COMMENT '状态 1-正常 0-禁用';这条语句的意思很直白:加一个status列,类型是TINYINT(小整数,取值范围-128到127,适合存状态码、标志位),NOT NULL表示不允许为空,默认值是1。执行完可以执行DESC students;查看表结构,确认新字段已经加上。
还有一个高频操作是修改字段。比如想把phone字段从20长度扩到30:
ALTER TABLE students MODIFY COLUMN phone VARCHAR(30) COMMENT '手机号';注意使用MODIFY时,除了标明的长度修改,其他属性要保持一致,否则会被改掉。有一种做法是先DROP COLUMN再加回,但这会丢数据,而且会重建表,操作期间可能锁表,在生产环境要尽量避免。实际操作中我遇到过一次这个坑,紧急加完字段后发现要把一个字段改回允许NULL,因为直接ALTER TABLE xxx MODIFY xxx INT NOT NULL会把已有数据全搞挂。改表结构这种操作,强烈建议先在测试环境跑一遍,确认无误再上生产。
重命名表有两种方式,一种是ALTER TABLE students RENAME TO student_info;,一种是用RENAME TABLE students TO student_info;。两者功能类似,但RENAME TABLE可以在一条语句里对多张表做重命名。需要注意的是,重命名后会影响到引用这张表的视图、存储过程、外键定义,牵一发动全身。
DROP TABLE的操作和DROP DATABASE一样,没有确认,没有回收站。实务上如果需要删除大批数据,优先考虑TRUNCATE TABLE,它是清空表数据但保留表结构,比DELETE FROM逐行删除快得多。但注意TRUNCATE属于DDL,执行后不可回滚,且会让AUTO_INCREMENT从头计数。
4.3 DML实操:INSERT、UPDATE、DELETE的细节
DML是程序员用得最多的操作,每个语句都有细节和坑。
INSERT有几种写法。最基础的单行插入:
INSERT INTO students (name, gender, birth_date, phone) VALUES ('张三', '男', '2005-06-15', '13800138001');多行插入可以这样写,一次插入多条记录,用逗号隔开:
INSERT INTO students (name, gender, birth_date, phone) VALUES ('李四', '女', '2006-03-22', '13800138002'), ('王五', '男', '2005-11-08', '13800138003');多行插入比逐行INSERT执行效率高很多,因为减少了客户端和服务器之间的网络往返。插入几千条数据的时候,一条多值INSERT比几千条单值INSERT快一个量级。
还有一种写法是INSERT INTO ... SELECT ...,把查询结果直接插入目标表。在数据迁移、表结构重建、临时表转正式表时极其常用。
INSERT有个容易踩的坑,就是字符集不一致导致的乱码和数据截断。如果表的字符集是utf8mb4,而连接字符集是latin1,中文插进去就成了“???”。出现这种情况,先执行SET NAMES utf8mb4;调整当前会话的字符集,再检查表和字段的字符集配置。
UPDATE语句,标准写法是:
UPDATE students SET status = 0 WHERE id = 3;这里最大的坑是忘记写WHERE。一句话更新全表所有记录,执行完你会看到Query OK, 1000 rows affected,然后想死的心都有。课程里给的防护建议是在测试环境先写SELECT确认影响范围,再改成UPDATE执行。
-- 先确认要更新的记录 SELECT * FROM students WHERE status = 1; -- 确认无误后再执行更新 UPDATE students SET status = 2 WHERE status = 1;另外UPDATE还能配合JOIN做跨表更新,比如根据班级表的数据批量更新学生表的班级ID,这个对新手稍微有点绕,不过本章节暂未展开,后面章节会专门讲。
DELETE语句:
DELETE FROM students WHERE id = 100;不加WHERE的DELETE等于清空全表,风险比UPDATE还大,因为数据直接没了。如果只是清空全部数据但保留表结构,用TRUNCATE效率更高。如果需要删除数据并且希望AUTO_INCREMENT继续顺着当前序号往下走,那用DELETE;如果希望重置自增ID从1开始,用TRUNCATE。
DELETE和UPDATE都属于DML,在InnoDB下支持事务回滚。一个不错的习惯是,在比较重要的批量操作之前先START TRANSACTION;,操作后先SELECT确认结果,确认无误再COMMIT;,发现不对立刻ROLLBACK;。这个习惯能救回过不少次错误操作。
提示:针对UPDATE和DELETE这类危险操作,一个比较稳妥的执行流程是:事务开启 -> SELECT 预查 -> UPDATE/DELETE -> SELECT 复查 -> COMMIT。这条链路下来,基本可以避免大多数手滑事故。
4.4 DQL实操:SELECT的常用子句串讲
SELECT是SQL里内容最多、最灵活的部分,课上用一张学生表把常用子句过了一遍。
最简单的查询:
SELECT * FROM students;*表示所有列,写起来省事,但生产环境不推荐。表里字段动不动二三十个,有些字段甚至是大文本或者二进制数据,全查出来既浪费带宽又拖慢性能。正确的习惯是只查需要的字段:
SELECT id, name, gender FROM students WHERE status = 1 ORDER BY id DESC LIMIT 20;这条语句包含了几个核心子句,它们的执行顺序是固定的,面试经常考:
- FROM:确定从哪张表取数据
- WHERE:过滤行,筛选符合条件的记录
- GROUP BY:分组
- HAVING:过滤分组后的结果
- SELECT:确定要查询的列,可能包含聚合函数
- ORDER BY:排序
- LIMIT:限制返回的行数
实际执行顺序和书写顺序不完全一致,这是很多新手理解SQL时困惑的点。比如WHERE不能使用SELECT里定义的别名做过滤,原因就是WHERE在SELECT之前执行。这是各大厂面试SQL基础时的高频考点。
聚合函数是DQL的重要组成部分。常用的是COUNT(计数)、SUM(求和)、AVG(平均值)、MAX(最大值)、MIN(最小值):
SELECT COUNT(*) AS total, AVG(age) AS avg_age, MAX(age) AS max_age FROM students;AS后面是别名,可以让结果集列名更清晰。这里有个细节,COUNT()和COUNT(字段名)有区别:COUNT()统计所有行,包括NULL;COUNT(字段名)只统计该字段非NULL的行。如果字段定义了NOT NULL,两者结果一样;如果允许NULL,结果会不一样。统计行数优先用COUNT(*)或者COUNT(主键)。
GROUP BY用来分组统计,比如按性别统计人数:
SELECT gender, COUNT(*) AS cnt FROM students GROUP BY gender;写GROUP BY的时候有个经典报错——ONLY_FULL_GROUP_BY。MySQL 5.7以及8.0默认开启这个模式,select列表里的非聚合列必须出现在GROUP BY子句中。类似SELECT name, gender, COUNT(*) FROM students GROUP BY gender;这种SQL,在5.7和8.0下会直接报错,但在低版本MySQL下可能不报错但结果不确定。
ORDER BY注意排序规则的影响。前面提到排序规则_ci结尾的大小写不敏感,所以直接ORDER BY name时,a和A会排在一起分不清先后。如果需要区分大小写排序,可以使用ORDER BY name COLLATE utf8mb4_bin,或者用BINARY关键字强制二进制比较。
LIMIT的语法在MySQL里有两个参数:LIMIT offset, count,offset表示跳过多少行,count表示取多少行。比如分页查询第2页、每页20条就是LIMIT 20, 20。MySQL 8.0也支持LIMIT 20 OFFSET 20这种更可读的写法。
一个实用的去重场景,课上特意提了一句:
SELECT DISTINCT gender FROM students;DISTINCT可以去重返回不重复的结果。注意DISTINCT是对整行的所有列做去重,不是单独对某一列去重。如果只想对某一列去重但显示其他列,不能靠DISTINCT,得用GROUP BY配合其他聚合手段。
4.5 DCL实操:账号权限管理的常用套路
DCL在日常开发里用得不多,但偶尔需要给自己建一个只读账号,或者给其他同事开一个临时账号,这时候就派上用场了。
创建用户:
CREATE USER 'readonly_user'@'localhost' IDENTIFIED BY 'StrongP@ssw0rd';这里'readonly_user'@'localhost'表示该用户只能从本机连接。如果要从任意主机连接,把localhost换成%。IDENTIFIED BY指定密码。
给用户授权:
GRANT SELECT ON school_db.* TO 'readonly_user'@'localhost';这表示给这个用户在school_db库里所有表上的SELECT权限,只读账号就建好了。school_db.*是库表级别的权限粒度,还能细到列级别,但日常很少用到。授权的常用权限大概有这些:
| 权限名 | 作用范围 | 说明 |
|---|---|---|
| SELECT | 行数据 | 查询 |
| INSERT | 行数据 | 插入 |
| UPDATE | 行数据 | 更新 |
| DELETE | 行数据 | 删除 |
| CREATE | 库/表 | 建库建表 |
| ALTER | 表 | 修改表结构 |
| DROP | 库/表 | 删库删表 |
| INDEX | 表 | 建索引 |
| ALL PRIVILEGES | 全局 | 所有权限,谨慎给 |
撤销权限:
REVOKE SELECT ON school_db.* FROM 'readonly_user'@'localhost';修改密码在MySQL 8.0里的语法和5.7不一样,8.0推荐这样:
ALTER USER 'readonly_user'@'localhost' IDENTIFIED BY 'NewPassword123';删除用户:
DROP USER 'readonly_user'@'localhost';DCL的核心原则是最小权限原则。线上环境只给业务账号它真正需要的权限,能不给DROP就不给DROP,能只读就只读。权限给多了,一旦账号密码泄露,后果就很严重。关于SQL注入的问题,课程里并没有展开讲,但我在后面的学习中有个深刻的体会:再强的数据库权限管控,也拦不住代码里直接把用户输入拼进SQL的做法。如果应用代码里存在注入点,攻击者就算只有一个只读账号,也能把整库数据拖走。DCL权限只是防线之一,代码层的防御同样重要,后面课程里专门会有一节讲这个问题。
5. 实操过程中的几个典型案例与排查记录
5.1 案例一:ERROR 1046 No database selected
现象:执行任何表操作都报错ERROR 1046 (3D000): No database selected。
原因:登录数据库后,没有执行USE school_db;切换当前库,或者当前会话的默认库已经断开。
解决:执行USE school_db;,或者在每条SQL前显式指定库名,写成SELECT * FROM school_db.students;。这里库名.表名这种写法叫全限定名,在任何库下都能直接访问目标表,不需要切换。
这类问题在编写自动化脚本时值得特别留意。脚本里可以先写USE xxx;固定切换库,或者干脆全部用全限定名,避免脚本在错误的库上执行导致“张冠李戴”。
5.2 案例二:中文乱码
现象:INSERT中文后,SELECT出来是???。
原因:字符集链路出了问题。MySQL涉及三处字符集:客户端字符集、连接字符集、服务端和数据库字符集。只要有一环不是utf8mb4,就可能乱码。
排查思路:先执行SHOW VARIABLES LIKE 'character_set%';看各个字符集设置,确认数据库、表、字段都是utf8mb4。如果数据已经写入乱码,先改字符集设置,再删除乱码数据重新插入。
解决:在登录时指定--default-character-set=utf8mb4参数,或者在会话里执行SET NAMES utf8mb4;。另外在建库建表时显式指定CHARACTER SET utf8mb4,从源头解决。
注意:
SET NAMES utf8mb4只对当前会话生效,断开重连后就失效了。如果希望长期稳定,最好客户端工具侧也统一配置,比如命令行登录时加--default-character-set=utf8mb4。
5.3 案例三:ONLY_FULL_GROUP_BY报错
现象:执行GROUP BY查询时报错which isn't in GROUP BY。
原因:MySQL 5.7及以上默认开启ONLY_FULL_GROUP_BYsql_mode,SELECT的列必须完整出现在GROUP BY子句中,或者被聚合函数包裹,否则SQL不合法。
解决:最正确的做法是改SQL,而不是关sql_mode。把不在GROUP BY里的列要么去掉,要么用聚合函数包起来,比如MAX(created_at)。
这类报错在低版本MySQL迁移到8.0的时候特别常见。老项目写在5.6下的SQL,可能靠着宽松模式跑得好好的,迁到8.0直接一排报错。正确姿势是逐个修正SQL,不推荐关闭ONLY_FULL_GROUP_BY,因为它能拦住不少写错的SQL,帮你规避结果不确定的查询。
5.4 案例四:ALTER TABLE修改字段时丢属性
现象:ALTER TABLE执行成功后,字段的注释、默认值等属性变了。
原因:MODIFY COLUMN会用你写的完整定义替换旧的字段定义,没写的属性会被重置为默认值,或者直接用默认设置覆盖。
解决:写MODIFY语句时,把目标字段的完整属性全部带上,包括类型、是否为空、默认值、注释。比如要改了长度,就要一次性把NOT NULL、DEFAULT、COMMENT全部写上。这点我踩过两次坑之后才学乖,每次ALTER操作都像重新建字段一样写完整定义。
实务中ALTER TABLE操作在大表上要特别小心,即使只是加一个字段,也可能需要重建表结构,锁表期间业务写入会被阻塞。比较大的表做结构变更,要评估好窗口期,尽量避开业务高峰期执行。更专业的做法是用gh-ost或者pt-online-schema-change这类工具做在线变更,但这是后话。
5.5 几个命令行操作心得
课程里穿插了不少命令行操作心得,挑几个印象深的记录一下。
第一个,命令行里执行SQL,结尾分号不能丢。MySQL的客户端交互终端,只有输入分号才表示一条SQL命令结束并执行,忘记分号按回车,终端会继续等你输入下一行。初学者经常敲完SQL直接回车,然后看着->提示符一脸懵,以为卡住了,其实是还没发出去。
第二个,用\G代替分号结尾,结果会纵向显示。字段多了以后,横向表格会被截断,可读性很差。用\G结尾,每行字段变成一行key: value,尤其适合看表结构或者单条记录的详细信息。
第三个,历史命令。在MySQL终端里可以用上下方向键翻历史命令,也可以敲\h查看帮助。写复杂SQL的时候,用笔记本先整理好SQL,再粘贴到终端执行,比直接在里面敲效率高得多,而且不容易出错。
第四个,退出MySQL终端的命令是EXIT;或者QUIT;,也可以用快捷键Ctrl+D。每次上完课记得退出连接,特别是远程服务器上的MySQL,挂着一堆空闲连接会白白消耗服务器资源。
6. 课后复习建议与扩展阅读思路
上午这34节课的内容,是MySQL学习过程中最基础的一块基石。建库、建表、增删改查、权限管理,几乎所有的业务开发都绕不开这些操作。掌握了这些基本功,后续的学习才稳当。
课后复习有几个方向可以扩展。第一个,把课堂演示的SQL全部自己手敲一遍,不要复制粘贴,手敲的过程中你会自然发现很多细节问题。第二个,自己创建一张和业务相关的表,比如订单表或者商品表,尝试把课上学的各类SQL都在这张表上跑一遍,特别是多表关联查询,这个后面会专门开课题讲,但提前在单表上练好基础是必要的。第三个,扩展阅读MySQL官方文档中CREATE DATABASE和SELECT语句的部分,官方文档虽然枯燥,但准确性最高。
个人建议,想深入理解MySQL的同学,可以试着在本地把binlog打开,然后用mysqlbinlog工具去看DML操作产生的日志记录。当你看到一条INSERT语句在binlog里是怎么记录的,你对MySQL的底层机制会有直观得多的认识。这一步跨过去,很多概念都变得立体起来。
再有就是日常工作中养成复盘的习惯。每次遇到一个SQL相关的报错,解决之后用一句话记下来——报错信息、原因、解决办法。积累个半年,这就是你最宝贵的技术财富。一个报错信息搜百度十分钟解决,但是第二次遇到同样的问题还要搜十分钟,就是在浪费时间。记录让别人去搜,你应该一眼认出它。