你第一次打开 MySQL 命令行,敲下的第一句 SQL,大概率不是查询,而是对着黑糊糊的终端发呆:我该把数据放哪?答案很简单——先建一个"库"(database),再把表和数据往里装。数据库是整个存储体系的第一层容器,是最顶层的那间"仓库"。后面学的一切(表、记录、索引、事务)都建立在它之上。

这篇文章我们只讲一件事:库的操作。从语法最朴素的 CREATE DATABASE 开始,一路走到字符集、排序规则、查看、修改、删除,最后是每个 DBA 和开发都要会的动静最大、也最需要谨慎的备份与恢复。你会清楚地知道"建库时为什么常写 utf8mb4""乱码和库的字符集到底什么关系""DROP 一下为什么容易被开除",以及"备份和恢复到底怎么玩转"。

你应该有的知识准备

开始前,有几样东西我们先碰个面,看不懂也没关系,正文里都会展开:

  • SQL 语言:Structured Query Language,结构化查询语言,是操作关系型数据库的通用标准语言。MySQL 支持它。
  • 客户端 / 服务器:MySQL 分"服务器"(mysqld,真正存数据的进程)和"客户端"(比如命令行 mysql)。你敲 SQL 是发给服务器执行的。备份工具 mysqldump 也是一名客户端,只不过它把整个库"导"成一个 SQL 文件。
  • 终端基本操作:会切换目录、用 > 做重定向(把输出写进文件)。备份环节绕不开它。
  • 一句能跑通的 SQL:比如 SELECT 1;。如果这条能返回结果,说明你的客户端和服务器已经连上了,下面的练习就行得通。

如果你已经建过库、插过几行数据再看这篇,会特别顺;如果你是纯新手,也完全够用,我们是从"什么是库"讲起的。

什么是"数据库",什么是"库"

先厘清一个最容易打架的措辞。"数据库"这个词有两种指代:广义上它是一套管理系统(我们常说"MySQL 数据库",指的是 MySQL 这个软件系统,全名叫 Database Management System,数据库管理系统,缩写 DBMS);狭义上它是指一个具体的命名空间,也就是一条 CREATE DATABASE 语句建出来的那个东西。

本文讲的就是狭义的那种:搜索引擎、学校系统里一个个独立命名的"库",比如 school、mall、blog。在 MySQL 里,库本质上是一个物理文件夹(在数据目录下,每个库对应一个同名目录,Windows 上装到例如 D:/mysql-5.7.22/data/school)。你往库里建表,就是在这个目录里放对应的表结构、表数据文件。

所以"库"像一个收纳箱:你在箱子里再放一个个"表"(相当于标签页/列表格),表里才有真正的一行行数据。创建表和数据之前,必须先进到一个库里。后面你会反复看到 USE 库名; 这条命令——它就是"把当前工作台切到这个库里"的意思。

创建数据库:CREATE DATABASE

建库的语法在 MySQL 官方文档里叫 CREATE DATABASE,它属于DDL。

DDL 是什么? DDL 全称 Data Definition Language,数据定义语言。它描述数据库"长什么样",而不是"里面有什么数据"。CREATE(创建)、ALTER(修改)、DROP(删除)都是 DDL 的成员。与之相对的是 DML(Data Manipulation Language,数据操纵语言),负责增删改查那几条(INSERT、DELETE、UPDATE、SELECT)。记住这个大框架,后面看到"这张表看看 DDL"就不会懵。

完整语法长这样(我用注释逐段拆):

CREATE DATABASE            -- 关键字:创建数据库
  [IF NOT EXISTS]          -- 可选项:如果不存在才创建,存在就不报错
  db_name                  -- 数据库名,必填
  [create_specification [, create_specification] ...]  -- 可选项:一个或多个创建规格(字符集、校验规则)
;
 
-- 其中 create_specification(创建规格)可以是:
--   [DEFAULT] CHARACTER SET charset_name   指定字符集
--   [DEFAULT] COLLATE collation_name       指定校验规则

读语法时,记住一套"读谱约定":大写的是关键字(MySQL 不强制大写,但文档惯例用大写强调"这是保留字");[...] 是可选项,可有可无;... 表示可以重复多个;小写斜体是你要自己填的名字/值。这套约定不只是 MySQL,几乎所有数据库文档都用,学会了读哪家文档都流畅。

三个最简单的案例,我们把完整命令写出来并逐行注释:

-- 案例1:创建一个名为 db1 的数据库
create database db1;

你没给任何规格,MySQL 就用"默认配置"建库。早期的 MySQL(5.7 时代)默认字符集是 utf8、默认校验规则是 utf8_general_ci;而 MySQL 8.0 起,默认字符集变成 utf8mb4,默认校验规则是 utf8mb4_0900_ai_ci。是不是有点懵?别急,字符集我们下一大节专门讲,现在只要先记住"它会有一个默认值"这句话。

-- 案例2:创建名为 db2 的数据库,并明确指定使用 utf8 字符集
create database db2 charset=utf8;

charset=utf8 是 CHARACTER SET utf8 的简写等价写法,意思是"这个库里的字符串默认按 utf8 编码来存"。为什么我们要"指定"而不指望默认?因为不同版本默认不同,显式写清楚,行为才可预期、不随环境漂移。

-- 案例3:创建名为 db3 的数据库,同时指定字符集 utf8 和校验规则 utf8_general_ci
create database db3 charset=utf8 collate utf8_general_ci;

collate 指定校验规则。这里我们把字符集和排序规则在同一条语句里都写明了——这两者在 MySQL 里通常成对出现、必须匹配(一种字符集对应若干种合法的排序规则,不能混用)。

为什么建议显式指定字符集才不乱码

这是本节最该刻进脑子里的一句话:库的字符集,会成为它内部默认的"编码语言",会一路继承给表、给列、给最后存的字符串。 所以你建错了字符集,麻烦不是在建库那一刻显现,而是几个月后在某个中文栏位突然输入中文变成 ??? 或者写入一堆乱码时才爆发。

怎么理解"字符集控制用什么语言"?字符集(Character Set)就是"一个字符用什么数字来表示"的编码表。 拿最相关的 utf8 举例:它规定"中、字"这类汉字和字母数字在计算机里各自对应哪一段字节序列。如果客户端往服务器发的字节,和服务器认为的字符集对不上,服务器就会"错位解读",于是你看到乱码。中文想要正常存储和显示,字符集至少得认识汉字。

这里有个必须科普的高频大坑:MySQL 里的 utf8 其实不是完整的 UTF-8,它只是"能表示 3 字节以内字符"的 UTF-8 子集(官方术语叫 utf8mb3),存 emoji 或者某些生僻字(它们需要 4 字节)会直接报错过不了。真正完整、能容纳所有 Unicode 字符的是 utf8mb4(mb = multibyte,多字节)。所以生产环境、以及所有面向用户输入中文 + 表情符号的场景,都推荐用 utf8mb4 而不是 utf8。这也是 MySQL 8.0 把默认字符集从 utf8 升级成 utf8mb4 的根本原因。

给你一个"建库标准姿势"模板,照着写基本不出格:

-- 推荐:显式指定 utf8mb4 字符集,并带上配套的校验规则
create database mall default character set utf8mb4 default collate utf8mb4_general_ci;

注意到我加了 default。在 CREATE DATABASE 里,DEFAULT CHARACTER SET 和 CHARACTER SET 是等价的,写不写 default 都行,属于文档推荐的可选写法,功能一致。utf8mb4_general_ci 是 utf8mb4 下一个通用、不区分大小写的校验规则,兼容性好、用得广;如果你想要 MySQL 8 更新更强的规则,可以用 utf8mb4_0900_ai_ci(基于 Unicode 9.0,ai=accent-insensitive 不管重音、ci=case-insensitive 不管大小写)。记住核心:库=字符集+排序规则的默认值工厂,建库时定好,全库的乱码风险源就定住了一大半。

字符集和排序规则

这一节是库操作的理论核心。我们把字面搞明白,你就不会再被一堆 _ci、_bin、_ai 后缀吓到。

字符集 vs 排序规则,到底谁是谁

两个概念容易混淆,一句话分清:

  • 字符集(Character Set):解决"怎么存"——字符 ↔ 二进制字节的映射编码。它管"能不能存得进来、存进去是不是我要的那个字"。
  • 排序规则(Collation,也译作"校验规则/排序规则"):解决"怎么比"——两个字符串相遇时,怎么判断相等、怎么排先后。它管"查询相等匹配的大小写敏感性、ORDER BY 的排列顺序"。之所以叫"校验规则",是因为字符串比较在 SQL 术语里也叫"校验/比对"。

打个比方:字符集是"中文、英文各有各自的字典"(同一份文本用不同字典翻出的码不同);排序规则是"字典里词条按什么次序排列"(是不区分大小写地按字母排,还是严格按 ASCII 码排)。

MySQL 里,一个字符集通常对应多种可选的排序规则,命名规律高度可读,拆开就懂。拿 utf8_general_ci 举例:

  • utf8:它服务的字符集是 utf8;
  • general:规则类型,general 指"通用、取舍较宽"的一套比较逻辑;
  • ci:case-insensitive,不区分大小写。

再看几个帮你读名的后缀:

  • ci = case-insensitive,不区分大小写;
  • cs = case-sensitive,区分大小写;
  • bin = binary,按二进制字节原样比较(因为直接比字节,大小写自然区分);
  • ai = accent-insensitive,不区分重音(对中文意义不大,主要是拉丁语系的重音字母)。

所以 utf8_general_ci 中文全称是"utf8 字符集下、通用规则、不区分大小写"的排序规则;utf8_bin 是"utf8 字符集下、按二进制比较"的排序规则。

查看 MySQL 默认的库字符集与排序规则

想知道当前服务器把"库"的默认值定成什么,用 SHOW VARIABLES 查两个系统变量:

-- 查看当前"数据库"这个对象的默认字符集
show variables like 'character_set_database';
 
-- 查看当前"数据库"这个对象的默认排序规则
show variables like 'collation_database';

SHOW VARIABLES 是"列出系统配置变量",配合 LIKE '...' 用通配符模糊匹配你想看的变量名。这两个变量 character_set_database、collation_database 就是"新建库若不指定时用谁"的答案。

查看 MySQL 支持哪些字符集和排序规则

想看看服务器到底装了几十种字符集分别叫什么,两条命令:

-- 列出所有支持的字符集,可看名称、描述、最大字节数、默认排序规则
show charset;
 
-- 列出所有支持的排序规则,数量巨大,可用 LIKE 过滤出某个字符集下的
show collation;
 
-- 只看 utf8mb4 字符集下有哪些排序规则(免得输出太多刷屏)
show collation like 'utf8mb4%';

SHOW CHARSET 的输出列里有个 Maxlen(最大字节数),你一眼就能看出 utf8 的 Maxlen 是 3、utf8mb4 的 Maxlen 是 4——这就是前面说的"utf8 存不下 4 字节字符"的直接证据。

排序规则对查询的影响:不区分 vs 区分大小写

空讲没感觉,我们建两个结构完全相同、仅排序规则不同的库做对照实验。关键步骤我都写成 SQL 并注释:

-- 建 test1:排序规则用 utf8_general_ci(不区分大小写)
create database test1 collate utf8_general_ci;
 
-- 切进 test1 库
use test1;
 
-- 建一张极简表 person,只有一个姓名列 name,字符类型 varchar(20)
create table person(name varchar(20));
 
-- 插入四行:小写 a、大写 A、小写 b、大写 B
insert into person values('a');
insert into person values('A');
insert into person values('b');
insert into person values('B');
-- 建 test2:排序规则用 utf8_bin(区分大小写 / 按二进制比)
create database test2 collate utf8_bin;
 
-- 切进 test2 库
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');

先做等值查询实验——用 where name='a' 查名字等于小写 a 的人。

在 test1(不区分大小写)里:

-- test1:where 条件是 name='a'(小写)
use test1;
select * from person where name='a';

结果:

+------+
| name |
+------+
| a    |
| A    |
+------+
2 rows in set (0.01 sec)

查一个小写 a,却把大写 A 也查出来了——因为 utf8_general_ci 认为 a 和 A 是同一个字符。这也许合你心意,但也可能正是你不想看到的(比如查用户名,大小写本应区分)。

再在 test2(区分大小写)里做同样查询:

-- test2:同样的查询,换到 utf8_bin 的库里
use test2;
select * from person where name='a';

结果:

+------+
| name |
+------+
| a    |
+------+
1 row in set (0.01 sec)

这次只返回了那一行小写 a,大写 A 被排除了。同一句 SQL、同一批数据,只因库里排序规则不同,结果就不同。 这正是排序规则直接影响业务判断的活例子。

再看排序实验——order by name 把名字排个序。

test1(不区分大小写):

-- test1:按 name 排序,a 与 A 视作相等,保持插入时的相对先后
use test1;
select * from person order by name;

结果:

+------+
| name |
+------+
| a    |
| A    |
| b    |
| B    |
+------+

test2(区分大小写):

-- test2:按 name 排序,直接按二进制字节(ASCII 码)排:A(65) B(66) a(97) b(98)
use test2;
select * from person order by name;

结果:

+------+
| name |
+------+
| A    |
| B    |
| a    |
| b    |
+------+

看出门道了吗?test2 里大写字母整体排在小写前面,因为二进制比较下大写 A``B 的字节值(ASCII 65、66)小于小写 a```b(97、98);而 test1 里重名时大小写权重相等,于是按插入顺序 a A b B 呈现。

现在的结论足够你实战用了: 建库时选排序规则,先问一句"这个库的文本,查询和排序要不要对大小写敏感"。多数中英文业务选不区分大小写的 _ci 即可,意即用户名不区分 Admin/admin;而需要严格区分的场景(口令、标识符、某些日志),就用 _bin 或 _cs。

查看数据库

建好、改好之后怎么"复盘"?MySQL 给了几条查看命令。

列出所有数据库:SHOW DATABASES

-- 列出当前服务器上存在的所有数据库名
show databases;

输出的样子大致是:

+--------------------+
| Database           |
+--------------------+
| information_schema |
| mall               |
| mysql              |
| performance_schema |
| sys                |
| test1              |
| test2              |
+--------------------+

注意不是每个库都是你自己建的。除了 mall、test1、test2 这几个业务库,剩下的 information_schema(元数据信息库)、mysql(系统权限库,存放用户、权限表)、performance_schema(性能监控库)、sys(封装性能视图的库)是 MySQL 自带的系统库,千万别去乱动、更别 DROP。真正的"我建的库"就是你认识的那几个名字。

显示建库时的完整定义:SHOW CREATE DATABASE

有时候你想看某个库当初到底带了什么字符集、什么排序规则,用 SHOW CREATE DATABASE:

-- 显示 mysql 这个库的创建语句(这里用 mytest 举例,请换成本机真实库名)
show create database mytest;

输出:

+----------+--------------------------------------------------------------------------+
| Database | Create Database                                                          |
+----------+--------------------------------------------------------------------------+
| mytest   | CREATE DATABASE `mytest` /*!40100 DEFAULT CHARACTER SET utf8 */         |
+----------+--------------------------------------------------------------------------+

这行 "CREATE DATABASE" 就是"若要我重建它,该怎么写"的标准答案,也是查看库当前字符集的可靠手段(比猜默认值靠谱)。

这里有两个反直觉的细节值得拆开:

第一,库名两边的反引号 ` 不是装饰,是有用的。CREATE DATABASE \mytest`中的反引号是用来**转义标识符**的——万一你的库名恰好撞上了 MySQL 的保留字(比如建一个叫order或select` 的库),不带反引号就会语法错误,带上反引号 MySQL 才认它是"普通名字而非关键词"。所以工具生成的建库语句一律给库名加反引号,是一种保险性习惯。

第二,/*!40100 ... */ 不是注释。虽然它长得像 C 语言那种 /*...*/ 块注释,但 /*! 开头的这种叫做"版本化注释"(versioned comment):只有当 MySQL 版本号 ≥ 40100(即 4.01 或以上)时,里面的内容才会被当作真正的 SQL 执行;版本不够就整体跳过。40100 读作"4.01.00"。这样一份 dump 文件既能在老版本 MySQL 上被安全跳过新语法、也能在新版本上正确执行,是兼容性手段。你以后打开备份生成的 .sql 文件会经常撞见它。

另外,MySQL 建议关键字用大写,但并非强制——大小写不敏感的关键字写小写照样执行。不过"库名/表名字段本身"在 Windows 上对大小写比较宽容、在 Linux 上区分大小写,这是另一条命名纪律,注意区分:"关键字的命名习惯"与"标识符的大小写敏感性"是两码事。

修改数据库:ALTER DATABASE

"库已经建了,结果当时忘写 utf8mb4、或者迁了环境要改字符集,怎么办?"——用 ALTER DATABASE。对库的修改,核心就两类:改字符集、改排序规则。语法和建库几乎一模一样,只是把 CREATE 换成 ALTER:

-- 语法:ALTER DATABASE 库名 [修改规格...]
-- 修改规格:
--   [DEFAULT] CHARACTER SET charset_name    改字符集
--   [DEFAULT] COLLATE collation_name        改排序规则
ALTER DATABASE db_name
  [DEFAULT] CHARACTER SET charset_name
  [DEFAULT] COLLATE collation_name;

实例:把 mytest 库的字符集从 utf8 改成 gbk(gbk 是中文最常用的双字节编码之一):

-- 把 mytest 库的字符集改为 gbk
alter database mytest charset=gbk;

回显 Query OK, 1 row affected,表示库的默认配置被改了。立刻用上一条 SHOW CREATE DATABASE 复核:

-- 复核:再看 mytest 的建库语句,字符集应已变成 gbk
show create database mytest;

输出:

+----------+------------------------------------------------------------------+
| Database | Create Database                                                  |
+----------+------------------------------------------------------------------+
| mytest   | CREATE DATABASE `mytest` /*!40100 DEFAULT CHARACTER SET gbk */  |
+----------+------------------------------------------------------------------+

看到末尾从 utf8 变成了 gbk,修改成功。

这里有个必须强调的边界:ALTER DATABASE ... CHARACTER SET 改的是库的默认值——它影响的是"这个库里以后新建表、新建列时,若不显式声明就继承的字符集"。它不会回头把库里已经存在的旧表、旧列、旧数据的存储编码也一起改写。旧数据要彻底转码,得在表/列层面再造或转换。所以"改库字符集就以为乱码全好了",往往是又一个坑:库的默认值只是"出厂配置",已成形的表要单独处理。 记牢,别把 ALTER DATABASE 当成万能转换器。

删除数据库:DROP DATABASE,高危操作

有创建就有删除。语法:

-- 语法:删除一个数据库
DROP DATABASE [IF EXISTS] db_name;
-- 实际删除名为 mytest 的数据库
drop database mytest;
 
-- 安全写法:只有存在才删,不存在也不报错(避免脚本里一句误报中断)
drop database if exists mytest;

执行删除之后,会发生三件事,最好逐条认清后果:

  1. 数据库列表里看不到它了——SHOW DATABASES 不再有这个库;
  2. 对应的物理文件夹被删除——磁盘上那个库目录没了;
  3. 级联删除,里面的表、数据、视图、存储过程全都没了——这是最要命的一条。

一句话总结危险:DROP DATABASE 是一键清空整个容器,无确认、无回收站、连带所有表和数据物理消失。

所以规范里白纸黑字写着"不要随意删除数据库"。真到删的时候,至少做到两步:先备份(用下一节的 mysqldump 把库导出来留底),在能确认"这个库确定不要了"的前提下才执行 DROP。另外给库命名时也好想清楚——别在开发环境随手建一堆 tmp123,删都删不过来还容易误删真的。IF EXISTS 会让语句在库不存在时安静跳过而不是抛错误,这在写自动化脚本、跑批时很常用,本质是一种"幂等"保护。

备份与恢复

终于到了动静最大的部分。任何"库操作"教程,备份与恢复都该被放到压轴——因为它是你数据安全的最后一道防线。备份(backup):把数据库当前的内容,导成一个独立的文件保存下来;恢复(restore,也叫还原):在需要时,用这个文件把数据重新灌回 MySQL。备份是"存",恢复是"取",两个动作配合,才能做到"出事了能回来"。

MySQL 最常用、也几乎是标准操作的备份工具是命令行程序 mysqldump。它是个逻辑备份工具,原理是:连接数据库,把整个"建库语句 + 建表语句 + 每个表逐行的 INSERT 语句"整个导出成一个纯文本 .sql 文件。你把这个文件打开看,会发现里面正是你亲手写过的建库建表语句和插入语句——也就是说,备份文件本质上是一个"可以原样回放的 SQL 剧本"。

注意:mysqldump 是在操作系统命令行里运行的一个独立程序,不是 MySQL 客户端里的内部命令。所以它要退出 MySQL 的 mysql 命令行界面,回到系统的命令提示符(PowerShell / cmd / shell)再执行。这是新手最容易卡住的点:在 mysql> 提示符里敲 mysqldump 会直接报"命令找不到 / Not found"。

备份整个数据库

基本语法与实例(在系统命令行执行,用 # 表示这是一行 shell 命令而非 SQL):

# 语法:-P 端口,-u 用户名,-p密码(不加空格),-B 数据库名,
#      > 右侧是重定向:把 mysqldump 的输出写进一个备份文件
mysqldump -P3306 -u root -p密码 -B 数据库名 > D:/mytest.sql
# 实例:把 mytest 库备份到 D 盘根目录下的 mytest.sql 文件
# 密码 123456 直接跟在 -p 后(-p123456,中间不能有空格)
mysqldump -P3306 -u root -p123456 -B mytest > D:/mytest.sql

这条命令执行完,在 D:/mytest.sql 里就能看到建库、建表、导入数据的整套 SQL。> 叫重定向(redirect / pipe):把命令本来要输出到屏幕的内容,转写到后面的文件里。这正是"导出成文件"的机制。

关于 -p 密码,分两种写法要记清:

  • -p123456:密码直接接在 -p 后面,不能有空格;
  • -p(后面不接):会**交互式地提示你输入密码**,安全得多,因为直接在命令行写明文密码会留在 shell 历史里,别人 history一眼看到。生产环境强烈建议用交互式-p` 而不把密码写进命令。

还有一个必须科普的安全写法

备份文件会带上 -B 标志,而 -B 的含义是 --databases:它会在导出内容里额外写上 CREATE DATABASE 和 USE 语句。这意味着——恢复的时候连建库都不用你操心,文件自己会先建库再选库里插数据,你只要负责把文件喂进去就行。这个细节直接决定了"恢复是否需要先手动建空库",后面重点说。

恢复整个数据库

恢复要用 MySQL 客户端内置的 source 命令(意思是"执行这个 SQL 脚本文件"),所以你得先登录进 mysql>:

-- 在 mysql 客户端内执行:把备份文件整个跑一遍
mysql> source D:/mytest.sql;

由于备份时带了 -B(文件内含建库+USE 语句),所以这个 source D:/mytest.sql 会一气呵成地把库建好、建好表、导入全部数据。你用 SHOW DATABASES(查看库列表)和 SELECT * FROM 某表;(查看表数据)就能验证恢复成功。

关键注意点:备份与恢复必须配套理解

这是本节最需要"掰开揉碎"的知识,分三点说透:

第一,整个库的备份,恢复务必配 -B。 上面我们看到的备份命令带了 -B,导出文件里写了建库语句,恢复时 source 一遍就行,库都不用预先建。但如果你备份时没带 -B,导出文件里就只有建表和 INSERT,没有建库语句。此时你恢复就得多做两步:先用 CREATE DATABASE 库名; 建一个空库(字符集要跟原来一致),再用 USE 库名; 切进去,最后才 source。否则文件里的 CREATE TABLE 会因为没有库可放而报错。一句话记规律:备份带 -B,恢复省心;备份不带 -B,恢复要自己建库选库。

第二,单表备份不带 -B。 如果只想备份某几个表而不是整个库,语法是(注意:不带 -B):

# 语法:备份 db_name 库下的 表1、表2 两张表
mysqldump -u root -p 数据库名 表名1 表名2 > D:/备份文件名.sql
# 实例:备份 mytest 库下的 person 表到 D:/person.sql
mysqldump -u root -p mytest person > D:/person.sql

因为单表备份没有 -B,所以恢复时按"注意点一"来:必须先有一个 mytest 库,USE mytest 进去,再 source D:/person.sql。这也反过来说明了一个实用结论:-B 参数是"整库级别"的专属,单表级别无法享受"自动建库"的便利。

第三,同时备份多个数据库,每个都带 -B。 想一次导多个库,把多个库名跟在 -B 后面即可:

# 语法:-B 后面可跟多个库名,一次性备份多个库到一个文件
mysqldump -u root -p -B 数据库名1 数据库名2 ... > 数据库存放路径
# 实例:把 db1 和 db2 两个库一起备份到 D:/db_backup.sql
mysqldump -u root -p -B db1 db2 > D:/db_backup.sql

此时多个库的建库 + 建表 + 数据都会装进同一个文件,恢复时同样靠 source 一次全灌回去(文件里每个库自带 CREATE DATABASE + USE)。

把三条注意点串起来的核心心法是:你的备份方式(带不带 -B、整库还是单表),决定了你的恢复流程(要不要先建库、要不要先 USE)。备份和恢复永远是一对兄弟命令,同一套参数配套使用,切记别"带 -B 备份、恢复时不建库"或者反过来。

一个完整的备份→毁库→恢复演练

纸上谈兵不如操练一遍。完整走一遍流程,你会有肌肉记忆(shell 命令和 SQL 混着用,我按顺序标出来):

# 第1步:在系统命令行,把 mytest 库带 -B 完整备份
mysqldump -P3306 -u root -p -B mytest > D:/mytest_bak.sql
-- 第2步:登录 MySQL
mysql -u root -p
 
-- 第3步:(模拟灾难)删掉 mytest 库,数据全部消失
drop database mytest;
 
-- 第4步:确认库里没了(列表里不再有 mytest)
show databases;
 
-- 第5步:用备份恢复——文件自带建库建表,直接 source 即可
source D:/mytest_bak.sql;
 
-- 第6步:验证库回来了
show databases;
 
-- 第7步:切进库,随便查一张表,数据应当原样还在
use mytest;
select * from person;

演练完你就明白:真正的恢复能力=备份文件的可靠 + 恢复步骤的熟练。平时就该演练过,别等事故临头才第一次 source。

查看连接情况:SHOW PROCESSLIST

库操作的最后补一个实用小工具。怀疑有人连到你的 MySQL、或者库变慢了,用 SHOW PROCESSLIST 看"当前都有哪些连接在干活":

-- 列出当前所有 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:是哪个用户(root 等);
  • Host:从哪个主机来的(localhost 是本地,出现陌生 IP 就要警惕);
  • db:当前正在使用(USE)的是哪个库,NULL 表示还没选库;
  • Command:该连接正在做什么命令(Sleep 是空闲挂着、Query 是正在执行查询);
  • Time:这个状态持续了多久(单位秒);
  • Info:正在执行的 SQL 文本(空闲时是 NULL)。

它的实战价值有两点:第一,安全排查——show processlist 能告诉我们当前有哪些用户连接到我们的 MySQL,如果查出某个连接的用户、来源主机不是你正常登陆的,很可能你的库被人入侵了,要赶紧查权限、改密码、踢连接。第二,性能排查——发现自己数据库比较慢时,用这条命令看是否有大量 Sleep 挂着不给、或某条 Query 卡了很久没跑完,据此定位是慢查询还是连接泄漏。

库操作的命名规范与综合注意事项

散件讲完了,汇总成一份"库操作自查清单",方便你以后照单办事:

  • 命名纪律:库名尽量语义化、小写、用下划线分词(如 school_course),别用空格、特殊符号和保留字当库名。真要用保留字,记得用反引号包住。
  • 字符集选择:中文业务默认 utf8mb4(完整 UTF-8,能存 emoji 和生僻字)而不是 utf8;需要跨 MySQL 8 与 5.7 兼容可用 utf8mb4_general_ci,追求 MySQL 8 最新规则可用 utf8mb4_0900_ai_ci。
  • 排序规则取向:多数业务选不区分大小写 _ci;标识符、口令等严格要求大小写区分的用 _bin。记住"建库定默认、继承到表列"。
  • 查看强迫症:建完、改完、恢复完,都用 SHOW CREATE DATABASE 库名 / SHOW DATABASES 复核一下,"眼见为实"。
  • 修改要自知:ALTER DATABASE ... CHARACTER SET 只改库的默认值,不回头转码已有表的存量数据。
  • 删除三连问:真要 DROP,先备份、再确认这个库确定不要、IF EXISTS 保脚本安全。
  • 备份成习惯:整库备份带 -B 恢复省心,单表备份不带 -B 恢复要自己建库 USE;-p 别在命令行写明文密码。

练习与自测(附详解答案)

把知识点落成几道题,每道我都给了完整解析,建议先动手再做看答案。

题1:我输入 create database db1; 建库,完全没有指定字符集。请问这个库会用哪个字符集?在不同版本下的答案会一样吗?

点开看详解

答案:用的是"服务器的默认库字符集"。在 MySQL 8.0 及之后,默认是 utf8mb4;在 5.7 及更早,默认是 utf8(严格说是 utf8mb3)。

解析:CREATE DATABASE 不写 CHARACTER SET 和 COLLATE 时,会套用系统变量 character_set_database 和 collation_database 的当前值,这两个变量可以用 SHOW VARIABLES LIKE 'character_set_database'; 查看。正因为不同版本默认不同,才强调"建库显式指定字符集",让行为可预期、不随版本漂移。

题2:utf8_general_ci 和 utf8_bin 这两种排序规则,在"查询相等匹配"和"排序输出"上有何不同?请各举一例说明。

点开看详解

答案:utf8_general_ci 是不区分大小写的(后缀 ci=case-insensitive);utf8_bin 是按二进制字节比较的,大小写严格区分。

解析:等值查询上,同在 where name='a' 条件下,_ci 的库里会把 a 和 A 都查出来(a 与 A 视为相等),_bin 的库只返回小写 a。排序上,_ci 认为 a、A 权重相同,排列不分家;_bin 按 ASCII 字节排,大写字母(A=65、B=66)整体排在小写(a=97、b=98)前面,所以 _ci 排序结果可能是 a A b B,_bin 排序结果是 A B a b。工程含义:用户名、邮箱这类无论大小写都应被认出同一用户时用 _ci;需要严格区分大小写的口令、标识符匹配则用 _bin。

题3:DROP DATABASE mytest; 执行后会发生什么?为什么说它是高危操作?

点开看详解

答案:它会把 mytest 库连同内部所有的表、数据文件在物理层一起删除,且没有确认弹窗、没有回收站,删除后不可直接撤销。

解析:删除后,SHOW DATABASES 里不再有该库,磁盘上对应的库目录也被删掉,库内一切对象(表、记录、视图、存储过程)因"级联删除"全部消失。因此操作前必须确认"这个库确定不要了",并养成"先 mysqldump 备份留底、再 DROP"的习惯。DROP DATABASE IF EXISTS mytest; 则会在库不存在时安静跳过,适合放进自动化脚本做幂等清理。另外要特别提醒:mysql(系统权限库)等自带库乱 DROP 会导致服务器异常,千万别碰。

题4:我用 mysqldump -u root -p mytest person > D:/p.sql 备份了 mytest 库中的 person 表。现在想在另一台机器上恢复这张表,请写出完整步骤。

点开看详解

答案:因为在单表备份时没有带 -B,备份文件里只有建表和 INSERT 语句、没有建库语句,所以恢复必须手动建库并选中库,再 source。完整流程:

-- 第1步:在目标机器上登录 MySQL(假设已能连接)
mysql -u root -p
-- 第2步:建一个和原来同名的库(字符集保持一致),不存在才建,安全
create database if not exists mytest default character set utf8mb4;
 
-- 第3步:切进这个库
use mytest;
 
-- 第4步:执行备份脚本,把表和 INSERT 灌回来
source D:/p.sql;

解析:source 是 mysql 客户端内执行 SQL 脚本的命令。由于单表备份不带 -B,脚本里没有 CREATE DATABASE 与 USE,如果目标机器上没有 mytest 库或没执行 USE mytest,脚本里的 CREATE TABLE person 会因"没有可用的库"而报错。这正是"备份与恢复参数配套"的体现:整库备份带 -B 恢复省心;单表备份不带 -B 恢复要自建库、自 USE。

题5:请你解释备份命令里 > 作用是什么,以及 -B 参数在备份与恢复中所扮演的角色。

点开看详解

答案:> 是 shell 里的重定向(redirect)符号,把本会打印到屏幕的命令输出,转写到它右侧的文件中,从而实现"把备份导出成文件"。-B 即 --databases,它让导出内容里额外带上每个库的 CREATE DATABASE 与 USE 语句,从而使恢复端 source 一遍即可自动建库、切库、建表、导数据,无需手动预建空库。

解析:例如 mysqldump -P3306 -u root -p -B mytest > D:/mytest.sql,没有 > 时备份内容会哗哗打到屏幕上;有 > 后全部进文件。带了 -B 则文件内开头会包含建库语句,恢复直接 source 完成;若不带 -B,恢复要先手动 CREATE DATABASE + USE 再 source。一句话记牢:备份用哪种方式(带不带 -B),恢复就要配套用哪种流程。

题6:为什么中文业务建库更推荐 utf8mb4 而不是 utf8?这两者在字节能力上差在哪?

点开看详解

答案:因为 MySQL 的 utf8 实际是 utf8mb3,一个字符最多用 3 字节,无法表示需要 4 字节的字符(emoji 表情、部分生僻汉字等),一插入这些字符就可能报错或乱码;而 utf8mb4 一个字符最多 4 字节,是完整覆盖 Unicode 的 UTF-8 编码。

解析:mb 是 multibyte(多字节)的缩写,utf8mb4 表示"最多 4 字节的 utf8"。用 SHOW CHARSET; 看列表,utf8 的 Maxlen 列是 3、utf8mb4 的 Maxlen 是 4,一目了然。正因 utf8mb4 更完整,MySQL 8.0 才把默认字符集从 utf8 升级为 utf8mb4。所以面向用户输入(可能带表情符号)的中文业务,应显式声明 default character set utf8mb4,从源头避免"能建库、存中文 OK、一遇 emoji 就报错"的尴尬。

好了,从一句 CREATE DATABASE 出发,我们把 MySQL 库的操作完整走了一遍:知道了库是"字的默认值工厂"(字符集+排序规则),学会了创建、查看、修改、删除的成对命令,也见识了动静最大的备份与恢复,以及最后那道"查看连接、识别入侵"的防线。库是表和数据的地基,地基的"编码规则"定错了,会长久地影响上面的每一层——所以这篇文章真正想让你带走的,不是背语法,而是那一套"选字符集、谨慎 DROP、备份恢复配套"的工程判断力。

下一篇,我会带你进入库内部的那些"格子"——表,看它如何定义列、约束与主键,把数据稳稳当当地装进这个我们已经搭好的容器里。建好了库,就等表来填满了。