库的操作说白了就四件事:增、删、改、查。但真正值得停下来想一想的,是藏在背后的两个问题:
- 我敲下
create database d1;,硬盘上到底发生了什么?- 为什么同一条
select * from person where name='a';,在两个库里查出来的行数不一样?第一个问题的答案会让你彻底理解"库"和"目录"的对应关系;第二个问题的答案,是字符集(Character Set)和校验集(Collation)——这两个词,是这一篇的核心。
环境说明:示例在 MySQL 5.7 / 8.0 上都能跑;utf8在 8.0 里会被规范成utf8mb3,文中遇到时会标注。下文mysql>开头的是你在客户端里敲的,其余是 MySQL 的返回结果。
目录:
〇、先看全局:思维导图
一、库住在哪儿?——数据目录 /var/lib/mysql
二、创建数据库
2.1 语法
2.2 if not exists:一个纯粹为了"别报错"的选项
2.3 本质:创建数据库 = 创建一个目录
三、字符集与校验集:本篇最该搞懂的地方
3.1 两个概念
3.2 查看字符集与校验集
3.3 _ci 和 _bin:区分大小写的那道分水岭
3.4 校验规则对数据库的影响(对比实验)
四、建库时指定编码与校验规则
4.1 三种写法
4.2 建完怎么验证?去看 db.opt
4.3 就近原则:谁说了算?
4.4 那……我到底为什么要设置库的编码?
五、删除数据库
六、操纵数据库
6.1 查看数据库
6.2 显示创建语句
6.3 use:切换到某个库
6.4 select database():我当前在哪个库?
6.5 修改数据库
七、备份和恢复
7.1 为什么不能"直接拷目录"?
7.2 备份
7.3 还原
7.4 -B 到底加不加?
7.5 注意事项:只备份部分内容
八、查看连接情况
九、两条"别乱来"
9.1 别随意删库
9.2 别随意改库名
十、番外:MySQL 5.7 与 8.0 的元数据存放差异
附录:知识速查表
速查表 1:库操作命令总览
速查表 2:字符集与校验集
速查表 3:备份与恢复
速查表 4:常见报错对照
速查表 5:踩坑清单
〇、先看全局:思维导图
一、库住在哪儿?——数据目录/var/lib/mysql
在敲第一条 SQL 之前,先把"库"的物理位置钉死。
MySQL 是跑在 Linux 上的服务进程(mysqld),它把所有数据库都放在一个固定的数据目录里,默认是/var/lib/mysql。进去看看,你会发现一个极其朴素的事实——每一个数据库,就是一个同名的文件夹:
[root@localhost ~]# cd /var/lib/mysql [root@localhost mysql]# ls d1 d2 ibdata1 ib_logfile0 ib_logfile1 mysql performance_schema sysd1、d2是我们的库,mysql、performance_schema、sys是系统自带的库。
数据目录的实际位置取决于安装方式(源码编译、yum、apt、Docker 都可能不同),由配置文件里的
datadir参数指定,可用show variables like 'datadir';查询。
这个认知会一路用下去:库 = 目录。后面所有的"创建""删除",都可以在脑子里同步翻译成mkdir和rm -rf。
二、创建数据库
2.1 语法
CREATE DATABASE [IF NOT EXISTS] db_name [create_specification [, create_specification] ...] create_specification: [DEFAULT] CHARACTER SET charset_name [DEFAULT] COLLATE collation_name三条说明:
- 大写的表示关键字(关键字大写只是建议,不是必须);
[]是可选项,写语法时不要把它真的敲进去;CHARACTER SET指定数据库采用的字符集,COLLATE指定字符集的校验规则。
注意create database后面没有 s——这和查看语句刚好相反,show databases时必须带 s,初学者容易在两处各错一次。
2.2if not exists:一个纯粹为了"别报错"的选项
mysql> create database if not exists db1; Query OK, 1 row affected, 1 warning (0.00 sec)返回1 warning,因为db1已经存在了。这个选项的意思是:"如果它不存在,那我就创建;如果已经存在,我就不创建了,你也别报错。"加不加它,就是报错和警告的区别:
-- 不加:库已存在 → 直接报错 mysql> create database db1; ERROR 1007 (HY000): Can't create database 'db1'; database exists -- 加了:库已存在 → 只给个警告,语句安全地"空跑" mysql> create database if not exists db1; Query OK, 1 row affected, 1 warning (0.00 sec)为什么不干脆让它报错?因为脚本和初始化 SQL 文件里无法保证库是否已建过。有了它,脚本就能反复执行而不中断——这在还原场景里是刚需(第七节你会看到,mysqldump导出的文件里全是这种写法)。
2.3 本质:创建数据库 = 创建一个目录
这解释了一个常见疑问:"我能不能直接在/var/lib/mysql下mkdir一个目录来建库?"
答案是:技术上它真的能工作,但你打死都不要这么干。
-- 绝对不要这么做! [root@localhost mysql]# mkdir d3因为手动mkdir出来的目录没有在数据字典里登记,字符集、校验规则这些元信息全是缺的,MySQL 会认为它处于"半成品"的不一致状态;直接rm -rf掉库目录同样危险——MySQL 并不知道你干了什么。
结论:库的增删改查一律走 SQL。这不是"建议",是"必须"。
三、字符集与校验集:本篇最该搞懂的地方
3.1 两个概念
MySQL 存取数据时用到两套规则:
| 名称 | 英文 | 作用 | 何时生效 |
|---|---|---|---|
| 字符集 | Character Set | 决定数据怎么存(用哪种编码把字符变成字节) | 写入 / 存储时 |
| 校验集 | Collation | 决定数据怎么比(字符串之间如何比较、排序) | 读取 / 比较 / 排序时 |
字符集主要控制用什么语言,比如 utf8 就可以使用中文。
一个贴切的类比:字符集是"我们用什么语言写字",大家都约定用汉字写,那谁写的谁就能读懂;校验集是"我们用什么规则判断两个字一不一样",判断 "a" 和 "A" 是不是同一个字,不同规则给出的答案完全不同。
为什么两个都必须是统一的?因为存进去的东西,必须用同一套规则才能读出来。就像一段二进制,你按整数写进去的,将来就必须按整数读出来——按浮点数去读,数据就毁了,比较也无从谈起。
一句话记住:数据库无论对数据做任何操作,都必须保证操作和编码是一致的。
3.2 查看字符集与校验集
查看系统默认的字符集与校验规则(两种写法,效果一样):
-- 写法一:show variables mysql> show variables like 'character_set_database'; +------------------------+---------+ | Variable_name | Value | +------------------------+---------+ | character_set_database | utf8mb3 | +------------------------+---------+ mysql> show variables like 'collation_database'; +--------------------+--------------------+ | Variable_name | Value | +--------------------+--------------------+ | collation_database | utf8mb3_general_ci | +--------------------+--------------------+ -- 写法二:select @@变量名,更短 mysql> select @@character_set_database, @@collation_database;查看数据库支持的全部字符集:
show charset;查看数据库支持的全部校验规则(结果很长,用\G竖排看更舒服):
show collation;后两张表里,每个字符集下面都列着它能匹配的校验集,一一对应。比如gbk对应的默认校验集就是gbk_chinese_ci("简体中文、不区分大小写")。
关于
utf8与utf8mb3:结果里的utf8mb3就是老版本里那个utf8。MySQL 的utf8从来都不是完整的 UTF-8——它最多只存 3 个字节,存不了 emoji 这类 4 字节字符。8.0 起官方把它正名为utf8mb3,并推荐新项目一律用utf8mb4。看到utf8mb3_general_ci你要知道:这就是那个"不区分大小写的老 utf8"。
3.3_ci和_bin:区分大小写的那道分水岭
校验规则的名字里通常带一个后缀,最常见的就是这两个:
| 后缀 | 全称 | 含义 |
|---|---|---|
_ci | case insensitive | 不区分大小写 |
_bin | binary | 区分大小写(按字节的二进制值直接比) |
差别体现在哪?就是一个等号的事。往下看实验。
3.4 校验规则对数据库的影响(对比实验)
造两个库,唯一变量是校验规则。
不区分大小写——校验规则用utf8_general_ci:
create database test1 collate utf8_general_ci; use test1; create table person(name varchar(20)); insert into person values('a'); insert into person values('A'); insert into person values('b'); insert into person values('B');区分大小写——校验规则用utf8_bin:
create database test2 collate utf8_bin; use test2; create table person(name varchar(20)); insert into person values('a'); insert into person values('A'); insert into person values('b'); insert into person values('B');建表时没有指定字符集——它会自动继承所在数据库的设置。这正是实验成立的前提:两个库字符集相同,唯一变量就是校验规则。
对比查询
-- test1(utf8_general_ci):a 和 A 被当作同一个值 mysql> use test1; mysql> select * from person where name='a'; +------+ | name | +------+ | a | | A | +------+ 2 rows in set (0.01 sec) -- test2(utf8_bin):严格按字节匹配,只有小写 a 符合 mysql> use test2; mysql> select * from person where name='a'; +------+ | name | +------+ | a | +------+ 1 row in set (0.01 sec)结论:同一个where条件,在utf8_general_ci下返回 2 行、在utf8_bin下只返回 1 行——校验规则直接决定了比较结果。
为什么这个知识点值钱?因为"用户名 / 邮箱登录不区分大小写"是常见需求,"密码哈希 / 验证码必须区分大小写"也是常见需求。这些需求不需要你在业务代码里写
lower(),把列的校验规则定对就够了——这是数据库帮你守的规矩。
四、建库时指定编码与校验规则
4.1 三种写法
-- 1. 只用默认(不指定,跟随配置文件) create database d1; -- 2. 只指定字符集(校验规则会跟着字符集自动匹配一个默认值) create database d2 charset=utf8; -- 3. 字符集和校验规则都指定 create database d3 charset=utf8 collate utf8_general_ci;不指定时,系统使用默认值:字符集utf8,校验规则utf8_general_ci;只指定字符集时,校验规则会自动匹配一个默认值。
charset也可以写成character set;语法里的[DEFAULT]是可选的修饰词,写不写都一样:
create database d4 default character set utf8 default collate utf8_general_ci;⚠️拼写注意:指定校验规则的关键字是collate,不是collection,也不是collation。collate是动词,collation是它的名词形式,而collection是"集合"——完全不同的词,却坑过无数人:
mysql> create database d5 charset=utf8 collection utf8_general_ci; ERROR 1064 (42000): You have an error in your SQL syntax ...4.2 建完怎么验证?去看db.opt
在 5.7 及以前,建完库后进数据目录,会看到每个库文件夹里多了一个db.opt:
[root@localhost mysql]# cd d3 [root@localhost d3]# cat db.opt default-character-set=utf8 default-collation=utf8_general_ci就这么两行,这就是这个库"出生时"定下的编码规矩。
db.opt是 MySQL 5.7 的机制。8.0 把它取消了,改由系统表空间mysql.ibd统一保管——详见第十节。
4.3 就近原则:谁说了算?
配置文件和建库语句都指定了编码,听谁的?就近原则:
- 用户在建库(或建表)时手动指定了→ 用你指定的;
- 用户没指定→ 用配置文件里的默认值。
-- 配置文件默认是 utf8,但我就是要建个 gbk 的库 create database d_gbk charset=gbk collate=gbk_chinese_ci;4.4 那……我到底为什么要设置库的编码?
这是初学时最容易"知其然不知其所以然"的地方。三层继承关系讲清楚就通了:
配置文件(my.cnf) ↓ 决定 数据库(database) ← 库的字符集/校验集 ↓ 决定 表(table) ← 建表不指定时,继承库的设置 ↓ 决定 列(column) ← 建表不指定时,继承表的设置在配置文件里配,是为了改默认值——影响"创建数据库时的默认字符集和校验集";在建库时指定,是为了给这个库单独定调,因为未来在这个库里建的表,默认都会继承库的设置。
所以设置库的编码,本质上是在为库里即将出生的所有表预设好基因。原则很简单:建库时把编码定好,后面建表就完全不用操心。
五、删除数据库
DROP DATABASE [IF EXISTS] db_name;mysql> drop database d1; Query OK, 0 rows affected (0.00 sec)if exists和if not exists完全对称:库不存在时静默跳过,只给个警告不报错。
执行删除之后的结果有三层,一层比一层严重:
- 数据库内部看不到对应的数据库——
show databases;里没有了; - 对应的数据库文件夹被删除——
/var/lib/mysql/d1整个目录没了; - 级联删除,里面的数据表全部被删—— 库里曾经建过的所有表、表里的所有数据,一个不剩。
第三层才是真正要命的:drop database删的不只是"一个空壳",而是连同里面所有的表和数据一起。它没有回收站,没有确认弹窗,敲下去就没了。
注意:不要随意删除数据库。
这不是一句空话,是血泪教训。规范做法是删库之前先备份——先
mysqldump把库导出成文件(见第七节),确认备份完好之后,再执行drop。同理,rm -rf直接删数据目录这种"野路子"也请一并戒掉。
六、操纵数据库
6.1 查看数据库
show databases;6.2 显示创建语句
show create database 数据库名;mysql> show create database mytest; +----------+----------------------------------------------------------------+ | Database | Create Database | +----------+----------------------------------------------------------------+ | mytest | CREATE DATABASE `mytest` /*!40100 DEFAULT CHARACTER SET utf8 */| +----------+----------------------------------------------------------------+ 1 row in set (0.00 sec)这条输出里藏着三个细节。
- 细节一:MySQL 建议关键字大写,但不是必须的。
CREATE DATABASE和create database效果完全一样,大写只是为了让 SQL 更易读。 - 细节二:反引号
`是为了防关键字冲突。反引号是"标识符引用符",作用是告诉 MySQL:"这里面的东西是一个名字,别当关键字解析"。比如你非要建一个叫order或select的库/表/列,就必须用反引号包起来。日常开发建议别跟关键字撞车,但万一撞了,反引号能救你。 - 细节三:
/*!40100 ... */不是注释。
如果当前 MySQL 版本 ≥ 4.01.00,就执行里面的内容。
这是 MySQL 特有的"版本条件执行"语法。
为什么要这么写?
因为 SQL 文件需要在不同版本的 MySQL 之间流转(比如从 5.7 备份、在 8.0 还原):语句对老版本有意义 → 老版本执行它;语句老版本不认识 → 老版本忽略它,而且不会报错。所以备份文件里到处都能看到/*!xxxxx ... */。看到它不是"注释",是"条件代码",就不会误判了。
6.3use:切换到某个库
mysql> use d1; Database changeduse的语义是"我接下来要在这个库里干活了"。我习惯把它类比成 Linux 的cd:
use d1;≈cd /var/lib/mysql/d1
这不是巧合——use之后你执行create table时,MySQL 确实就是在对应目录下创建文件。库的行为和 Linux 文件系统的行为是可以对应上的。
⚠️ 一个高频报错:忘了use就开始建表。
mysql> create table t1(id int); ERROR 1046 (3D000): No database selected6.4select database():我当前在哪个库?
use了太久,容易忘了自己在哪儿。用这个函数确认:
mysql> select database(); +--------------+ | database() | +--------------+ | NULL | +--------------+ 1 row in set (0.00 sec)结果NULL说明你当前不在任何数据库里(比如刚登录还没use)。切过去之后再看:
mysql> use test2; Database changed mysql> select database(); +------------+ | database() | +------------+ | test2 | +------------+6.5 修改数据库
ALTER DATABASE db_name [alter_specification [, alter_specification] ...] alter_specification: [DEFAULT] CHARACTER SET charset_name [DEFAULT] COLLATE collation_name对数据库的修改,主要就是指修改它的字符集和校验规则:
mysql> alter database mytest charset=gbk; Query OK, 1 row affected (0.00 sec) mysql> show create database mytest; +----------+----------------------------------------------------------------+ | Database | Create Database | +----------+----------------------------------------------------------------+ | mytest | CREATE DATABASE `mytest` /*!40100 DEFAULT CHARACTER SET gbk */ | +----------+----------------------------------------------------------------+⚠️一个必须说清楚的点:alter database改的是这个库"之后建表时的默认值",也就是db.opt里那两行。
它不会去动这个库里已经建好的表——那些表在创建时就把编码定死了。想改已存在表的编码,得单独对它执行alter table(这属于会引起数据重建的操作,要慎重)。
另外,日常开发中alter database用得极少。因为库里一旦有了数据,编码改动牵一发动全身。编码这种事,应该在建库第一天就定好,而不是事后补救。
七、备份和恢复
7.1 为什么不能"直接拷目录"?
既然库就是一个目录,那我直接把/var/lib/mysql打个包,不就完成备份了?
技术上可以,但严重不推荐。原因很直白:跨版本的目录结构不兼容——你这边跑的是 5.7,备份出来的目录拿到一台跑 5.0 的机器上,文件格式很可能根本读不了。(用mv给库目录改名当备份?同样不推荐,原因见 9.2。)
正解:用 MySQL 自带的备份工具mysqldump。
7.2 备份
# mysqldump -P3306 -u root -p 密码 -B 数据库名 > 数据库备份存储的文件路径示例:把mytest库备份到文件(先退出连接):
mysqldump -P3306 -u root -p123456 -B mytest > D:/mytest.sql| 参数 | 含义 |
|---|---|
-P3306 | 指定连接端口号(P大写) |
-uroot | 指定用户名 root(u小写) |
-p | 提示输入密码 |
-B | 备份时带上"建库语句",详见 7.4 |
⚠️重要:mysqldump是一条操作系统命令,必须在终端里执行,不是在mysql>客户端里。这是新手最容易卡住的地方。
密码安全:课件示例写作
-p123456(密码直接跟在-p后面),能跑,但密码会明文出现在命令历史(history)和进程列表里,生产环境绝对不要这么写。正确姿势是只写-p,回车后再交互输入。
打开mytest.sql看看内容,其实把我们整个创建数据库、建表、导入数据的语句都装载这个文件中了:
CREATE DATABASE /*!32312 IF NOT EXISTS*/ `mytest` /*!40100 DEFAULT CHARACTER SET utf8 */; USE `mytest`; DROP TABLE IF EXISTS `person`; CREATE TABLE `person` ( `name` varchar(20) DEFAULT NULL ) ENGINE=InnoDB DEFAULT CHARSET=utf8; INSERT INTO `person` VALUES ('a'),('A'),('b'),('B');看出门道了吗?mysqldump备份的不只是数据,而是"重建这个库所需要执行的全部有效操作":建库 → 删旧表(保证可重复执行)→ 建表 → 插数据。所以恢复的本质,就是把这堆 SQL 再跑一遍。
7.3 还原
mysql> source D:/mysql-5.7.22/mytest.sql;source是mysql>客户端内部的命令(注意:和mysqldump刚好相反,这个要在客户端里执行),后面跟备份文件的完整路径。它的作用就是:把文件里的 SQL 语句,在这个 MySQL 里从头到尾执行一遍。
很实用的场景:把
.sql文件发给另一台机器上的同事,他本地没有这个库,直接source一下,数据库就在他那边重建出来了。这就是"用 SQL 文件在机器之间搬运数据库"。
7.4-B到底加不加?
-B(--databases的简写)决定备份文件里有没有建库语句。
情况一:不加-B
mysqldump -u root -p mytest > D:/mytest.sql导出的内容里只有CREATE TABLE和INSERT INTO,没有CREATE DATABASE和USE。恢复时直接跑这个文件会报错,因为MySQL 不知道要把这些表建到哪个库里。必须手动三步:
create database mytest; use mytest; source D:/mytest.sql;情况二:加了-B
文件开头会自动带上CREATE DATABASE /*!32312 IF NOT EXISTS*/ ...和USE ...,恢复时什么都不用管,直接source就全自动完成。
结论:除非你有特殊理由,备份时一律加
-B。多打两个字符,省下恢复时的一堆麻烦。
7.5 注意事项:只备份部分内容
只备份其中的一张表(或 N 张表):
mysqldump -u root -p 数据库名 表名1 表名2 > D:/mytest.sql这里没有-B——因为备份的不是整个库,恢复时要自己先建库、use进去,再source。
同时备份多个数据库:
mysqldump -u root -p -B 数据库名1 数据库名2 ... > 数据库存放路径带-B时后面可以跟多个库名,导出文件里会依次为每个库生成建库语句。
规律:不管是备份单表、多表、单库还是多库,备份命令的套路一样,恢复方式也一样。唯一要记住的就是-B那条分界线。
八、查看连接情况
有时候发现数据库比较慢、卡顿,第一反应应该是:现在有哪些人连着?在干什么?
mysql> show processlist; +----+------+-----------+------+---------+------+-------+------------------+ | Id | User | Host | db | Command | Time | State | Info | +----+------+-----------+------+---------+------+-------+------------------+ | 2 | root | localhost | test | Sleep | 1386 | | NULL | | 3 | root | localhost | NULL | Query | 0 | NULL | show processlist | +----+------+-----------+------+---------+------+-------+------------------+| 列 | 含义 |
|---|---|
Id | 连接的唯一编号 |
User | 是哪个用户在连 |
Host | 从哪台机器连过来的 |
db | 当前连的是哪个库(NULL表示没use任何库) |
Command | 当前在执行什么类型的命令(Query/Sleep/Daemon) |
Time | 该状态持续的秒数 |
State | 当前的具体状态 |
Info | 正在执行的 SQL 语句原文 |
它告诉我们当前有哪些用户连接到 MySQL。两个重要用途:
- 安全排查:如果查出某个用户不是你正常登录的,很有可能你的数据库被人入侵了;
- 性能排查:发现数据库比较慢时,盯着
Time列看——如果某条Query的Time一直很大,那条 SQL 就是嫌疑人。
九、两条"别乱来"
9.1 别随意删库
第五节讲过,但要再强调一次:drop database是级联删除,表和数据一起没。删之前先备份,这个顺序不能反。
9.2 别随意改库名
MySQL不提供数据库重命名功能。以前有过RENAME DATABASE,后来被移除了,原因就是"改库名这件事本身就很危险":你改的时候,可能别人正在用这个库。
更要命的是第二条:应用层对数据库的依赖,全都是通过"库名"这个接口的。回头看看你的项目——配置文件里的连接串、ORM 的映射、各种脚本……到处都写着库名。你把库名一改,上层的所有应用全部失效——这不是夸张,这就是所谓的蝴蝶效应。想在 Linux 层面用mv改名绕过?前面说过了,严重不推荐。
十、番外:MySQL 5.7 与 8.0 的元数据存放差异
前面提到的db.opt,在 8.0 里消失了。
MySQL 5.7 及以前:就像每个班级(数据库)自己拿个小本本(db.opt)记自己的规矩(字符集、校验规则),各自管各自的。
MySQL 8.0:取消了小本本。所有班级的规矩全部统一上交到学校的总档案室(系统表空间mysql.ibd),由校长(MySQL 服务)统一保管。
mysql.ibd是什么?它就是那个"总档案室",属于 InnoDB 的系统表空间。你创建的数据库名、它们各自的字符集和排序规则,以及所有表的结构信息(也就是数据字典),全部存在这个文件里。你没法用文本编辑器打开它,只能通过 SQL 语句去查。这也是 8.0 一个重要的架构改进:元数据有了统一、事务安全的管理方式。
对我们使用者的影响:8.0 里库目录下再也找不到db.opt了,想确认库的编码,请用show create database 库名;或select @@character_set_database;这类 SQL 手段。
附录:知识速查表
速查表 1:库操作命令总览
| 目的 | 语句 | 备注 |
|---|---|---|
| 查看所有库 | show databases; | 有 s |
| 创建库 | create database [if not exists] 库名; | 没有 s |
| 指定编码建库 | create database 库名 charset=utf8 collate utf8_general_ci; | 校验规则关键字是collate |
| 删除库 | drop database [if exists] 库名; | 级联删除,不可逆 |
| 切换库 | use 库名; | 相当于cd进目录 |
| 查当前库 | select database(); | 返回NULL表示不在任何库 |
| 看建库语句 | show create database 库名; | 能看到字符集 |
| 改库默认编码 | alter database 库名 charset=gbk; | 只影响之后建的表 |
| 看谁在连 | show processlist; | 排查入侵和慢查询 |
速查表 2:字符集与校验集
| 概念 | 作用 | 何时生效 |
|---|---|---|
| 字符集 Character Set | 数据怎么存 | 写入时 |
| 校验集 Collation | 数据怎么比 | 读取、比较、排序时 |
| 查看命令 | 作用 |
|---|---|
show variables like 'character_set_database'; | 当前库的字符集 |
show variables like 'collation_database'; | 当前库的校验规则 |
select @@character_set_database, @@collation_database; | 同上,更短 |
show charset; | MySQL 支持的全部字符集 |
show collation; | MySQL 支持的全部校验规则及对应关系 |
| 后缀 | 含义 | where name='a'会返回 |
|---|---|---|
_ci(case insensitive) | 不区分大小写 | a和A都返回 |
_bin(binary) | 区分大小写,按字节值比 | 只返回a |
继承链:
配置文件→数据库→表→列,上一层决定下一层的默认值。
速查表 3:备份与恢复
| 场景 | 命令 | 在哪执行 |
|---|---|---|
备份整个库(推荐加-B) | mysqldump -P3306 -uroot -p -B 库名 > 库名.sql | 终端 |
| 备份多个库 | mysqldump -uroot -p -B 库1 库2 > multi.sql | 终端 |
只备份某几张表(不加-B) | mysqldump -uroot -p 库名 表1 表2 > t.sql | 终端 |
| 恢复 | source /完整路径/文件.sql | mysql>客户端内 |
-B选项 | 备份文件里有建库语句吗 | 恢复时要做什么 |
|---|---|---|
加了-B | 有(CREATE DATABASE+USE) | 直接source,全自动 |
没加-B | 没有 | 必须先create database→use→ 再source |
速查表 4:常见报错对照
| 错误码 | 报错(节选) | 你踩了什么 |
|---|---|---|
1007 | Can't create database 'x'; database exists | 库已存在却没用if not exists |
1008 | Can't drop database 'x'; database doesn't exist | 删一个不存在的库,可加if exists |
1044 | Access denied for user ... to database ... | 当前用户没权限访问这个库 |
1046 | No database selected | 建表前忘了use 库名 |
1049 | Unknown database 'x' | use了一个不存在的库 |
1064 | You have an error in your SQL syntax ... | 语法错误:collate拼成collection等 |
1366 | Incorrect string value: ... for column 'x' | 字符集存不下你插的内容(典型:utf8存不了 emoji) |
速查表 5:踩坑清单
create database没有 s,show databases有 s—— 两边各错一次是常态。if not exists和if exists是为了让脚本可重复执行,不是用来替代错误处理的。- 数据目录里
mkdir/rm -rf手动增删库目录,技术上能跑,实践上绝对别干。 - 库 = 目录,
drop database= 删目录且级联删除里面所有表和数据,无回收站。 - 校验规则关键字是
collate,不是collection,也不是collation。 utf8在 MySQL 里是utf8mb3,最多 3 字节,存不了 emoji;新项目建议直接用utf8mb4。alter database改的是"以后建表的默认值",已存在的表不会跟着变。mysqldump在终端执行;source在mysql>客户端内执行 —— 两者刚好相反。- 备份一律加
-B,除非你只备份某几张表;不加-B恢复时得自己先建库。 -p后面不要紧跟密码,否则密码会进命令历史和进程列表。- MySQL不支持数据库重命名。库名一旦被上层应用依赖,改动就是蝴蝶效应。
show processlist里出现陌生用户,很可能数据库被人入侵了。