目录
- 一、SQL 语句基础
- 二、数据库操作
- 三、字符集与字符序
- 四、数据库对象与命名规范
- 五、表的基本操作
- 六、表的约束
- 七、存储引擎与完整建表语句
- 八、数据库账户与权限管理
- 九、综合练习
- 十、常见报错与命令速查
一、SQL 语句基础
1.1 什么是 SQL
SQL(Structured Query Language,结构化查询语言)是在关系型数据库上执行数据操作、数据检索、数据维护的标准语言。使用 SQL,程序员和数据库管理员可以完成:
- 改变数据库的结构;
- 更改系统的安全设置;
- 增加用户对数据库或表的许可权限;
- 在数据库中检索需要的信息;
- 对数据库的信息进行更新。
1.2 SQL 语句分类
MySQL 致力于支持全套 ANSI/ISO SQL 标准,常用语句可分为四类:
| 分类 | 全称 | 作用 | 典型语句 |
|---|---|---|---|
| DDL | Data Definition Language(数据定义语言) | 定义数据库对象(库、表、列、索引) | CREATE、DROP、ALTER、RENAME、TRUNCATE |
| DML | Data Manipulation Language(数据操作语言) | 操作表中的记录 | INSERT、DELETE、UPDATE、SELECT |
| DCL | Data Control Language(数据控制语言) | 控制库、表、字段、用户的访问权限和安全级别 | GRANT、REVOKE |
| 事务控制 | Transaction Control | 事务的提交与回滚 | COMMIT、ROLLBACK、SAVEPOINT |
记忆技巧:DDL 改结构、DML 改数据、DCL 管权限、TCL 管事务。
1.3 SQL 语句的书写规范
- SQL 关键字不区分大小写 (建议统一大写),但字符串常量区分大小写;
- SQL 语句可单行或多行书写,以英文分号
;结尾; - 关键字不能跨多行书写,也不能简写;
- 用空格和缩进来提高语句的可读性;
- 注释写法:
- 多行注释:
/* 注释内容 */ - 单行注释:
-- 注释内容(--后必须有空格)或# 注释内容
- 多行注释:
sql
-- 这是一个单行注释
/* 这是
多行注释 */
SELECT NOW(); # 查看当前时间
二、数据库操作
2.1 数据库的登录与退出
MySQL 服务需要先启动,否则客户端连接会报 ERROR 2002:
bash
[root@server ~]# systemctl start mysqld
[root@server ~]# mysql -uroot -p
Enter password:
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 16
Server version: 8.0.37 MySQL Community Server - GPL
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
登录格式:
bash
mysql -u用户名 -h服务器主机地址 -p密码
| 参数 | 含义 | 说明 |
|---|---|---|
-u |
登录用户名 | 例如 root |
-h |
服务器主机地址 | 本机可省略,或写 localhost / IP |
-p |
用户密码 | -p 与密码之间不能有空格 ,否则密码会被当成数据库名;不写密码时只写 -p,回车后再输入 |
登录成功后的提示信息含义:
Commands end with ; or \g:命令以;或\g结束,遇到结束符才开始执行;Your MySQL connection id is 16:当前是第几次连接;Server version: 8.0.37 ...:MySQL 服务器版本;Type 'help;' or '\h' for help:输入help;或\h查看帮助;Type '\c' to clear the current input statement:输入\c清除当前正在输入的命令(注意不是清屏)。
若服务未启动,会出现:
text
ERROR 2002 (HY000): Can't connect to local MySQL server through socket
'/var/lib/mysql/mysql.sock' (2)
退出 MySQL 有三种方式:
sql
exit
quit
\q
小提示:命令行直接写密码
mysql -uroot -p123456会提示Using a password on the command line interface can be insecure,生产环境不建议这样做。
2.2 查看数据库
sql
SHOW DATABASES;
SHOW DATABASES [LIKE '条件'];
MySQL 安装后自带的 4 个系统库:
| 数据库 | 作用 |
|---|---|
information_schema |
数据字典,存储用户表信息、列信息、权限信息、字符集信息、分区信息等 |
performance_schema |
存储数据库服务器的性能参数 |
mysql |
存储系统的用户权限信息及帮助信息 |
sys |
MySQL 5.7 新增,通过视图把 information_schema 与 performance_schema 整合,查询更直观 |
LIKE 支持通配符:
%:匹配任意零个或多个字符;_:匹配任意单个字符。
sql
mysql> SHOW DATABASES LIKE 'sys';
mysql> SHOW DATABASES LIKE 's%';
mysql> SHOW DATABASES LIKE '__sql'; # 匹配 mysql
常用系统函数:
sql
mysql> SELECT NOW(); # 当前时间
mysql> SELECT VERSION(); # 数据库版本
mysql> SELECT USER(); # 当前登录用户及主机
+----------------+
| user() |
+----------------+
| root@localhost |
+----------------+
2.3 创建数据库
sql
CREATE DATABASE 数据库名;
CREATE DATABASE IF NOT EXISTS 数据库名; -- 推荐写法
示例:
sql
mysql> CREATE DATABASE testdb;
Query OK, 1 row affected (0.00 sec)
mysql> CREATE DATABASE testdb;
ERROR 1007 (HY000): Can't create database 'testdb'; database exists
查看建库语句:
sql
mysql> SHOW CREATE DATABASE testdb \G
*************************** 1. row ***************************
Database: testdb
Create Database: CREATE DATABASE `testdb` /*!40100 DEFAULT CHARACTER SET utf8mb4
COLLATE utf8mb4_0900_ai_ci */ /*!80016 DEFAULT ENCRYPTION='N' */
这条语句可以分为 3 段理解:
CREATE DATABASE \testdb``:创建数据库 testdb;/*!40100 DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci */:字符集使用utf8mb4(1~4 字节,可存 emoji),比较规则utf8mb4_0900_ai_ci中ai表示不区分重音、ci表示不区分大小写;/*!80016 DEFAULT ENCRYPTION='N' */:数据库未加密。
关于反引号:
- 只有保留关键字和特殊字符才必须用反引号;
- 普通表名、列名可加可不加,但为了代码规范建议统一;
- 反引号可以避免与 SQL 关键字冲突:
sql
mysql> CREATE DATABASE database;
ERROR 1064 (42000): You have an error in your SQL syntax; ... near 'database' at line 1
mysql> CREATE DATABASE `database`;
Query OK, 1 row affected (0.01 sec)
注意:创建数据库、查看建库语句时用的是
DATABASE(没有 s),而查看所有库时是SHOW DATABASES(有 s)。
2.4 切换数据库
sql
USE 数据库名;
SELECT DATABASE(); -- 查看当前使用的数据库
示例:
sql
mysql> USE testdb;
Database changed
mysql> SELECT DATABASE();
+------------+
| database() |
+------------+
| testdb |
+------------+
未选择任何数据库时,SELECT DATABASE() 返回 NULL。
2.5 删除数据库
sql
DROP DATABASE 数据库名;
DROP DATABASE IF EXISTS 数据库名; -- 推荐
sql
mysql> DROP DATABASE testdb;
Query OK, 0 rows affected (0.01 sec)
删除数据库会同时删除库中所有表和数据,生产环境务必先备份、并确认不在使用。
2.6 数据库操作小结
| 操作 | 命令 |
|---|---|
| 创建数据库 | CREATE DATABASE 数据库名; |
| 设为当前数据库 | USE 数据库名; |
| 查看当前数据库 | SELECT DATABASE(); |
| 显示所有数据库 | SHOW DATABASES; |
| 删除数据库 | DROP DATABASE 数据库名; |
三、字符集与字符序
3.1 字符集(Character Set)
字符集是字符的编码规则,规定了字符在数据库中的存储格式,例如占用多少空间、支持哪些字符。字符集选错,轻则影响性能,重则导致数据存储乱码。
- MySQL 5.7 默认字符集是
latin1; - MySQL 8.0 默认字符集是
utf8mb4; - 8.0 中建库建表、应用程序连接尽可能统一使用
utf8mb4(支持 emoji)。
字符集选型建议:
- 面向国外业务、需要处理多国语言:选
utf8mb4(或utf8); - 只需要支持中文、对性能敏感:可选
GBK; - MySQL 中的
utf8实际是utf8mb3的别名,不推荐使用。
常见字符集对比:
| 字符集 | 说明 |
|---|---|
latin1 |
支持西欧字符、希腊字符等 |
gbk |
支持中文简体,但不是国际通用字符集 |
big5 |
支持中文繁体 |
utf8 |
几乎支持世界所有国家字符,最多 3 字节 |
utf8mb4 |
完全兼容 UTF-8,用 4 字节存储更多字符(含 emoji) |
3.2 字符序(Collation)
字符序是字符排序的规则集合 ,主要影响字符串比较与排序结果。例如 A > B > a > b 和 a > b > A > B 就是两种不同的排序规则。
MySQL 字符序的命名规则:
- 以对应字符集名称开头;
- 中间是国家名(或以
general表示通用); - 后缀含义:
| 后缀 | 含义 |
|---|---|
bin |
二进制比较 |
ci |
大小写不敏感(case insensitive) |
cs |
大小写敏感(case sensitive) |
ai |
口音不敏感(accent insensitive) |
as |
口音敏感(accent sensitive) |
ks |
假名敏感(kanatype sensitive) |
例如 utf8mb4_0900_ai_ci:字符集 utf8mb4、Unicode 9.0 规则、不区分重音、不区分大小写。
3.3 查看字符集与字符序
sql
SHOW CHARACTER SET; -- 查看所有支持的字符集
SHOW CHARACTER SET LIKE 'gbk'; -- 查看指定字符集
SHOW CHARACTER SET LIKE 'utf%';
SHOW COLLATION; -- 查看所有字符序
SHOW COLLATION LIKE 'utf8mb4%';
SHOW CHARACTER SET 字段含义:
| 字段 | 含义 |
|---|---|
Charset |
字符集名称 |
Description |
简单描述 |
Default collation |
该字符集的默认字符序 |
Maxlen |
该字符集中字符的最大存储长度(字节) |
SHOW COLLATION 字段含义:
| 字段 | 含义 |
|---|---|
Collation |
字符序名称 |
Charset |
关联的字符集 |
Id |
字符序 ID |
Default |
是否为该字符集的默认字符序 |
Compiled |
是否已编译进服务器 |
Sortlen |
排序所需内存量相关 |
Pad_attribute |
比较时是否考虑末尾 padding |
3.4 查看当前字符集设置
sql
SHOW VARIABLES LIKE 'character_set%';
| 变量 | 含义 |
|---|---|
character_set_client |
客户端字符集 |
character_set_connection |
通信链路字符集,客户端请求以此编码 |
character_set_database |
数据库默认字符集(重要) |
character_set_filesystem |
文件系统字符集,固定为 binary |
character_set_results |
服务器返回结果使用的字符集 |
character_set_server |
服务器默认字符集(重要) |
character_set_system |
存储元数据使用的字符集 |
3.5 utf8 与 utf8mb4 的区别
MySQL 5.5.3 之后新增 utf8mb4,mb4 即 most bytes 4 ,专门兼容 4 字节 Unicode。utf8mb4 是 utf8 的超集。
- MySQL 的
utf8最大只支持 3 字节 ,三个字节最多编码到0xFFFF,即 Unicode 的基本多文种平面(BMP); - 不在 BMP 中的字符(如 emoji、部分生僻汉字)无法用
utf8存储,插入会报错或乱码; - 只改编码为
utf8mb4即可,无需做其他转换;一般情况下用utf8也够,但 8.0 之后建议直接使用utf8mb4。
四、数据库对象与命名规范
4.1 数据库对象的组成
MySQL 数据库对象包括:数据库(database)、表(table)、视图(view)、索引(index)、存储过程/函数(procedure/function)、触发器(trigger)、事件(event)等。
4.2 命名规则
- 使用有意义的英文词汇,单词之间用下划线分隔;
- 名称由字母、数字、
#、下划线、$组成,必须以英文字母开头; - 不要使用 MySQL 保留字;
- 所有数据库对象统一小写(MySQL 可设置大小写敏感,统一小写最稳妥);
- 同一个对象集合内不能重名;
- 命名尽量简短且能表达含义。
4.3 生产环境命名规范
数据库:
- 命名尽量不超过 30 个字符;
- 一般为「项目名称 + 库含义简写」,例如 IM 项目的工作流库:
im_flow; - 统一小写。
表:
| 类型 | 规则 | 示例 |
|---|---|---|
| 常规表 | t_ + 模块简写 + 表含义简写 |
用户模块教育信息表:t_user_eduinfo |
| 临时表 | temp_ + 模块 + 表 + 日期后缀 |
temp_user_eduinfo_20240520 |
| 备份表 | bak_ + 模块 + 表 + 日期后缀 |
bak_user_eduinfo_20231219 |
- 同一模块的表尽量使用相同前缀;
- 多个单词用下划线分隔;
- 常规表名尽量不超过 30 个字符,临时表/备份表视情况尽量简短;
- 统一小写。
五、表的基本操作
5.1 MySQL 数据类型
数据类型是建表的基础,选型是否合理直接影响存储空间和查询性能。MySQL 数据类型分为:数字、文本、日期/时间三大类。
5.1.1 整型
| 类型 | 字节数 | 有符号范围(默认) | 无符号范围(UNSIGNED) |
|---|---|---|---|
TINYINT |
1 | -128 ~ 127 | 0 ~ 255 |
SMALLINT |
2 | -32768 ~ 32767 | 0 ~ 65535 |
MEDIUMINT |
3 | -8388608 ~ 8388607 | 0 ~ 16777215 |
INT |
4 | -2147483648 ~ 2147483647 | 0 ~ 4294967295 |
BIGINT |
8 | -9223372036854775808 ~ 9223372036854775807 | 0 ~ 18446744073709551615 |
选型建议:为合适的列选择合适的数据类型 。例如一个只有 0/1 的枚举字段,用 TINYINT 就够,若用 BIGINT 就浪费了 7 字节;按 100 万行计算,约浪费 7MB,表多了浪费更可观。
关于 INT(N):
N只是显示宽度 ,与存储无关,INT永远占 4 字节;- 不足宽度补 0,超过宽度则完整显示;
- MySQL 8.0.17 之后已不推荐这种写法。
5.1.2 浮点型
| 类型 | 字节数 | 说明 |
|---|---|---|
FLOAT |
4 | 单精度浮点型 |
DOUBLE |
8 | 双精度浮点型 |
可以写成 FLOAT(M,D) / DOUBLE(M,D) 限制总位数 M 和小数位数 D(例如 FLOAT(3,2));不指定时按实际精度处理。
5.1.3 定点型
DECIMAL(size,d) 以字符串形式存储,不会出现精度丢失 。FLOAT/DOUBLE 存储的是近似值,可能出现「写入的值」和「查出来的值」不一致:
sql
mysql> CREATE TABLE t1(float_num FLOAT(10,2), double_num DOUBLE(20,2), decimal_num DECIMAL(20,2));
mysql> INSERT INTO t1 VALUES (1234567.66, 1234567899000000.66, 123456789000000.66);
mysql> SELECT * FROM t1;
+------------+---------------------+--------------------+
| float_num | double_num | decimal_num |
+------------+---------------------+--------------------+
| 1234567.62 | 1234567899000000.80 | 123456789000000.66 |
+------------+---------------------+--------------------+
可以看到 FLOAT/DOUBLE 发生了精度丢失,而 DECIMAL 没有。因此银行、互联网金融等对小数敏感的系统应使用 DECIMAL。
5.1.4 字符串类型
| 类型 | 说明 |
|---|---|
CHAR(size) |
固定长度字符串,0 ~ 255 个字符,不足补空格,取出时去掉尾部空格 |
VARCHAR(size) |
可变长度字符串,最大 65535 字节(受行长度和字符集限制) |
TINYTEXT |
最大 255 字节的文本 |
TEXT |
最大 65535 字节的文本 |
MEDIUMTEXT |
最大 16777215 字节的文本 |
LONGTEXT |
最大 4294967295 字节的文本 |
TINYBLOB / BLOB / MEDIUMBLOB / LONGBLOB |
二进制大对象,容量与对应 TEXT 相同 |
ENUM(x,y,z,...) |
枚举,最多 65535 个值,只能取列表中的一个 |
SET(x,y,z,...) |
集合,最多 64 个列表项,可存多个值 |
CHAR 与 VARCHAR 的选择:
CHAR适合固定长度内容:手机号、身份证号、性别等,查询效率高;VARCHAR适合长度不固定内容:姓名、地址、备注等,更节省空间;- 简单记忆:
CHAR定长、VARCHAR变长;名字、地址用VARCHAR,编码类用CHAR。
TEXT 与 BLOB 的区别:
TEXT以字符形式存储,有字符集和排序规则,适合存文章内容、评论等;BLOB以二进制形式存储,没有字符集和排序规则,适合存图片、文件等二进制数据。
5.1.5 日期/时间类型
| 类型 | 字节数 | 格式 | 说明 |
|---|---|---|---|
DATE |
3 | yyyy-MM-dd |
日期 |
TIME |
3 | HH:mm:ss |
时分秒 |
YEAR |
1 | yyyy |
年份 |
DATETIME |
8 | yyyy-MM-dd HH:mm:ss |
日期 + 时间 |
TIMESTAMP |
4 | yyyy-MM-dd HH:mm:ss |
日期 + 时间,可作时间戳(受时区影响) |
常用结论:
- 只需要日期用
DATE,需要精确到秒用DATETIME; TIMESTAMP占 4 字节、受时区影响,适合记录「最后更新时间」;- 金额、数量等精确数值不要用浮点型。
5.2 创建表
语法:
sql
CREATE TABLE [IF NOT EXISTS] 表名 (
列名1 列类型1 [约束],
列名2 列类型2 [约束],
...
[表级约束]
) [ENGINE=存储引擎] [DEFAULT CHARSET=字符集];
注意事项:
- 表默认创建在当前数据库中,建表前必须先用
USE 数据库名;选择数据库,否则报No database selected; - 表名不区分大小写,但不能使用 SQL 关键字(如
DROP、ALTER、INSERT); - 必须为每一列指定名称和数据类型,多列之间用逗号分隔。
示例:创建学生表
sql
mysql> CREATE DATABASE mydb2_stuinfo;
mysql> USE mydb2_stuinfo;
Database changed
mysql> CREATE TABLE student1(
-> id INT,
-> name VARCHAR(30),
-> sex CHAR(2),
-> age INT UNSIGNED,
-> score FLOAT,
-> addr VARCHAR(50));
Query OK, 0 rows affected (0.02 sec)
mysql> DESC student1;
+-------+--------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+--------------+------+-----+---------+-------+
| id | int | YES | | NULL | |
| name | varchar(30) | YES | | NULL | |
| sex | char(2) | YES | | NULL | |
| age | int unsigned | YES | | NULL | |
| score | float | YES | | NULL | |
| addr | varchar(50) | YES | | NULL | |
+-------+--------------+------+-----+---------+-------+
6 rows in set (0.00 sec)
示例:创建员工表
sql
mysql> CREATE DATABASE mydb3_employee;
mysql> USE mydb3_employee;
mysql> CREATE TABLE tb1(id INT, name VARCHAR(25), salary FLOAT);
Query OK, 0 rows affected, 1 warning (0.03 sec)
mysql> SHOW TABLES;
+--------------------------+
| Tables_in_mydb3_employee |
+--------------------------+
| tb1 |
+--------------------------+
5.3 查看表
sql
SHOW TABLES; -- 查看当前库的所有表
SHOW TABLES FROM 数据库名; -- 查看指定库的表
SHOW TABLES LIKE 'student%'; -- 按条件过滤
DESC 表名; -- 查看表结构(推荐)
DESCRIBE 表名;
SHOW COLUMNS FROM 表名; -- 等价写法
SHOW CREATE TABLE 表名 \G -- 查看完整建表语句
DESC 输出字段含义:
| 字段 | 含义 |
|---|---|
Field |
字段名称 |
Type |
字段类型 |
Null |
是否允许为空(YES/NO) |
Key |
索引类型(PRI 主键、UNI 唯一、MUL 普通索引) |
Default |
默认值 |
Extra |
附加信息,如 auto_increment |
SHOW CREATE TABLE 可以看到存储引擎、字符集、注释等完整定义:
sql
mysql> SHOW CREATE TABLE student1 \G
*************************** 1. row ***************************
Table: student1
Create Table: CREATE TABLE `student1` (
`id` int DEFAULT NULL,
`name` varchar(30) DEFAULT NULL,
`sex` char(2) DEFAULT NULL,
`age` int unsigned DEFAULT NULL,
`score` float DEFAULT NULL,
`addr` varchar(50) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci
5.4 删除表
sql
DROP TABLE [IF EXISTS] 表名;
sql
mysql> DROP TABLE tb1;
Query OK, 0 rows affected (0.01 sec)
mysql> DROP TABLE IF EXISTS tb1; -- 推荐写法,表不存在也不报错
Query OK, 0 rows affected (0.01 sec)
删除表前务必确认:
- 数据已备份,避免误删丢失;
- 表没有被其他表通过外键引用;
- 表数据确实不再需要;
- 相关程序已停止使用该表,避免影响业务。
5.5 修改表(ALTER TABLE)
5.5.1 修改表名
sql
-- 方式一
ALTER TABLE 旧表名 RENAME 新表名;
-- 方式二
RENAME TABLE 旧表名 TO 新表名;
sql
mysql> ALTER TABLE student2 RENAME student3;
Query OK, 0 rows affected (0.01 sec)
mysql> RENAME TABLE student3 TO teacher1;
Query OK, 0 rows affected (0.01 sec)
5.5.2 新增列
sql
ALTER TABLE 表名 ADD 新列名 列类型 [AFTER 列名 | FIRST];
AFTER 列名:在指定列之后插入(没有BEFORE关键字);FIRST:插入到第一列;- 不写位置时默认追加到最后一列。
sql
mysql> ALTER TABLE student1 ADD password CHAR(8);
Query OK, 0 rows affected (0.01 sec)
mysql> ALTER TABLE student1 ADD notes VARCHAR(30) AFTER age;
mysql> ALTER TABLE student1 ADD aa INT FIRST;
5.5.3 删除列
sql
ALTER TABLE 表名 DROP 列名;
mysql> ALTER TABLE student1 DROP notes;
mysql> ALTER TABLE student1 DROP aa;
5.5.4 修改列名
sql
ALTER TABLE 表名 CHANGE 旧列名 新列名 列类型;
注意 CHANGE 必须同时写上列类型,否则会语法报错;它也可以同时修改列名和类型。
sql
mysql> ALTER TABLE student1 CHANGE password passwd CHAR(8);
5.5.5 修改列类型
sql
ALTER TABLE 表名 MODIFY 列名 新列类型;
sql
mysql> ALTER TABLE student1 ADD birthday CHAR(10);
mysql> ALTER TABLE student1 MODIFY birthday DATE; -- 字符型改为日期型
5.5.6 修改列位置
sql
ALTER TABLE 表名 MODIFY 列名 列类型 AFTER 某列;
ALTER TABLE 表名 MODIFY 列名 列类型 FIRST;
小结:
ADD加列、DROP删列、CHANGE改列名、MODIFY改类型/位置。
5.6 复制表
| 方式 | 语法 | 结果 |
|---|---|---|
| 只复制结构 | CREATE TABLE 新表 LIKE 源表; |
结构完全一致,不含数据 |
| 结构 + 数据 | CREATE TABLE 新表 SELECT * FROM 源表; |
有数据,但主键、自增、索引等可能丢失 |
| 只复制数据 | INSERT INTO 新表 SELECT * FROM 源表; |
需先建好结构相同的表 |
sql
-- 1. 只复制表结构
mysql> CREATE TABLE student2 LIKE student1;
Query OK, 0 rows affected (0.01 sec)
mysql> SELECT * FROM student2;
Empty set (0.00 sec) # 只有结构,没有数据
-- 2. 复制表结构 + 数据
mysql> CREATE TABLE student3 SELECT * FROM student1;
Query OK, 0 rows affected (0.01 sec)
Records: 2 Duplicates: 0 Warnings: 0
-- 3. 只复制数据(先建好同结构表)
mysql> INSERT INTO student2 SELECT * FROM student1;
Query OK, 2 rows affected (0.00 sec)
5.7 数据字典 information_schema
数据字典类似于「系统编目 / 花名册」,保存数据库服务器的元数据(meta data,即「关于数据的数据」),包括库、表、字段、视图、用户、统计等属性信息。
information_schema 是 MySQL 自带库,提供访问元数据的方式,常用表:
| 表 | 说明 |
|---|---|
TABLES |
所有数据表及所属数据库 |
SCHEMATA |
所有数据库信息 |
COLUMNS |
所有列信息 |
VIEWS |
所有视图信息 |
TRIGGERS |
所有触发器 |
ROUTINES |
所有存储过程和函数 |
KEY_COLUMN_USAGE |
主外键信息 |
TABLE_CONSTRAINTS |
所有约束 |
STATISTICS |
索引信息 |
sql
mysql> USE information_schema;
mysql> SHOW TABLES;
mysql> SELECT TABLE_NAME, TABLE_COMMENT FROM TABLES WHERE TABLE_SCHEMA='mydb2_stuinfo';
通过 information_schema 可以了解整个 MySQL 实例的运行情况,用于查询元数据、优化调优、维护数据库。
5.8 建表练习
创建商品数据库 mydb4_product,建商品表 pro_tb1:
- 字段:编号
num INT、商品名trade_name VARCHAR(30)、数量number INT、单价price FLOAT(5,2); - 显示建表字段内容;
- 新增一列备注
notes VARCHAR(30)放在最后一列; - 将编号
num类型改为CHAR(4); - 删除该表(先判断是否存在)。
sql
mysql> CREATE DATABASE mydb4_product;
mysql> USE mydb4_product;
mysql> CREATE TABLE pro_tb1(num INT, trade_name VARCHAR(30), number INT, price FLOAT(5,2));
mysql> DESC pro_tb1;
mysql> ALTER TABLE pro_tb1 ADD notes VARCHAR(30);
mysql> DESC pro_tb1;
mysql> ALTER TABLE pro_tb1 MODIFY num CHAR(4);
mysql> DESC pro_tb1;
mysql> DROP TABLE IF EXISTS pro_tb1;
六、表的约束
6.1 为什么需要约束
数据类型本身对字段的约束很单一,很多业务规则无法表达:
- 字段是否可以为
NULL、有没有默认值; - 字段能否重复(如身份证号、学号必须唯一);
- 数值的取值范围(如年龄 0~120)。
约束(Constraint) 是在表上强制执行的数据校验规则,本质是 MySQL 通过限制用户操作来维护数据安全与完整性的一套方案。约束作为数据库对象存放在系统表中,也有自己的名字。
数据完整性主要从四个方面考虑:
| 完整性 | 含义 | 示例 |
|---|---|---|
| 实体完整性 | 不能存在两条完全相同的记录 | 主键 |
| 域完整性 | 字段取值在合理范围内 | 年龄 0~120、性别「男/女」 |
| 引用完整性 | 外键引用的数据必须存在 | 学生所在班级必须在班级表中存在 |
| 用户自定义完整性 | 业务规则 | 用户名唯一、密码不能为空 |
常见约束:非空(NOT NULL)、默认值(DEFAULT)、主键(PRIMARY KEY)、外键(FOREIGN KEY)、唯一(UNIQUE)、检查(CHECK)。
创建时机:建表时创建、建表后通过 ALTER TABLE 追加。约束可定义在列级 或表级。
6.2 约束语法
列级约束(定义列的同时定义约束):
sql
CREATE TABLE 表名 (列名 类型 约束);
ALTER TABLE 表名 MODIFY 列名 列类型 列约束; -- 添加
ALTER TABLE 表名 MODIFY 列名 列类型; -- 不加约束即删除
表级约束(所有列定义完之后定义):
sql
CREATE TABLE 表名 (列信息..., CONSTRAINT 约束名 约束类型(要约束的列));
ALTER TABLE 表名 ADD [CONSTRAINT 约束名] 约束类型(要约束的列); -- 添加
ALTER TABLE 表名 DROP 约束类型 约束名; -- 删除
约束命名推荐:
表名_列名_约束类型简介,例如t_user_id_pk。
6.3 非空约束(NOT NULL)
作用:限定某列的值不允许为空。取值只有 NULL(默认)和 NOT NULL。
- 所有数据类型的值都可以是
NULL; - 空字符串
''不等于NULL,数字0也不等于NULL; - 实际开发中尽量保证字段非空,因为
NULL无法参与运算。
sql
mysql> CREATE TABLE myclass1(
-> class_name VARCHAR(20) NOT NULL,
-> class_room VARCHAR(20) NOT NULL,
-> class_id INT);
mysql> INSERT INTO myclass1 (class_room) VALUES ('计科1');
ERROR 1364 (HY000): Field 'class_name' does not have a default value
mysql> INSERT INTO myclass1 (class_name, class_room) VALUES ('A104', '计科1');
Query OK, 1 row affected (0.00 sec)
已有表添加/删除非空约束:
sql
mysql> ALTER TABLE student1 MODIFY id INT NOT NULL; -- 添加
mysql> ALTER TABLE student1 MODIFY id INT NULL; -- 删除(NULL 可省略)
6.4 默认值约束(DEFAULT)
作用:给字段指定默认值,插入数据时若该字段没有显式赋值,则自动填充默认值。
sql
mysql> CREATE TABLE teacher1(
-> id INT NOT NULL,
-> name VARCHAR(30) NOT NULL,
-> sex CHAR(2) DEFAULT '女');
mysql> INSERT INTO teacher1(id, name) VALUES (1001, '林雪');
mysql> SELECT * FROM teacher1;
+------+--------+------+
| id | name | sex |
+------+--------+------+
| 1001 | 林雪 | 女 |
+------+--------+------+
表已存在时添加默认值:
sql
mysql> ALTER TABLE student1 MODIFY sex CHAR(2) DEFAULT '女';
注意:如果一个字段同时设置了
NOT NULL和DEFAULT,插入时不赋值会使用默认值,此时NOT NULL实际不会生效(因为永远有值)。
6.5 列描述(COMMENT)
列描述只起说明作用,会被保存在建表语句中,相当于 C/C++ 的注释,方便查看字段含义。
sql
mysql> CREATE TABLE myclass2(
-> class_name VARCHAR(20) NOT NULL COMMENT '教室',
-> class_room VARCHAR(20) DEFAULT '计科2');
mysql> SHOW CREATE TABLE myclass2 \G
Create Table: CREATE TABLE `myclass2` (
`class_name` varchar(20) NOT NULL COMMENT '教室',
`class_room` varchar(20) DEFAULT '计科2' COMMENT '班级'
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci
6.6 主键约束(PRIMARY KEY)
作用:唯一标识表中的一行记录。主键是最常用的约束。
特点:
- 主键字段不能为空、不能重复;
- 一张表最多只能有一个主键;
- 主键列通常是整数类型;
- 创建主键时,MySQL 会在该列上自动建立主键索引,删除主键约束时对应索引自动删除;
- 不要修改主键字段的值,否则可能破坏数据完整性。
建表时创建主键:
sql
mysql> CREATE TABLE t1 (
-> id INT UNSIGNED PRIMARY KEY COMMENT '学号不能为空',
-> name VARCHAR(20) NOT NULL,
-> sex CHAR(2) DEFAULT '男');
Query OK, 0 rows affected (0.02 sec)
mysql> DESC t1;
+-------+--------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+--------------+------+-----+---------+-------+
| id | int unsigned | NO | PRI | NULL | |
| name | varchar(20) | NO | | NULL | |
| sex | char(2) | YES | | 男 | |
+-------+--------------+------+-----+---------+-------+
mysql> INSERT INTO t1 VALUES (1, '孙文', '女');
mysql> INSERT INTO t1(id, name) VALUES (1, '黎明');
ERROR 1062 (23000): Duplicate entry '1' for key 't1.PRIMARY'
建表后追加主键(该列有重复值时会失败,需先去重):
sql
mysql> ALTER TABLE teacher1 ADD PRIMARY KEY(id);
删除主键:
sql
ALTER TABLE 表名 DROP PRIMARY KEY;
复合主键:多个字段联合起来作为唯一标识,单个字段可以重复,只要组合不冲突即可。
sql
mysql> CREATE TABLE t2 (
-> id INT,
-> hostname VARCHAR(10),
-> ip VARCHAR(20),
-> port INT UNSIGNED,
-> PRIMARY KEY(ip, port));
mysql> INSERT INTO t2 VALUES (1, 'node1', '192.168.48.2', 120);
mysql> INSERT INTO t2 VALUES (2, 'node2', '192.168.48.3', 120); -- 单个字段重复,OK
mysql> INSERT INTO t2 VALUES (3, 'node3', '192.168.48.2', 120); -- 组合冲突
ERROR 1062 (23000): Duplicate entry '192.168.48.2-120' for key 't2.PRIMARY'
6.7 主键自增长(AUTO_INCREMENT)
作用:给主键自动生成递增的数值,通常与主键搭配作为逻辑主键。
规则:
- 自增长字段必须是整数;
- 可以不设置初始值,默认从 1 开始递增;
- 被自增长的字段必须作为主键或唯一键(索引);
- 一张表最多只能有一个自增长列;
- 也可以手动插入不自增的值,之后从当前最大值继续递增。
sql
mysql> ALTER TABLE student1 ADD PRIMARY KEY(id);
mysql> ALTER TABLE student1 MODIFY id INT AUTO_INCREMENT;
Query OK, 3 rows affected (0.05 sec)
mysql> DESC student1;
+----------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+----------+--------------+------+-----+---------+----------------+
| id | int | NO | PRI | NULL | auto_increment |
+----------+--------------+------+-----+---------+----------------+
mysql> INSERT INTO student1(name) VALUES ('关六'); -- 不写 id,自动生成
指定自增起始值:
sql
mysql> CREATE TABLE t3 (
-> id INT PRIMARY KEY AUTO_INCREMENT,
-> systemname VARCHAR(10) NOT NULL
-> ) AUTO_INCREMENT = 100;
mysql> INSERT INTO t3(systemname) VALUES ('windows'), ('linux');
mysql> SELECT * FROM t3;
+-----+------------+
| id | systemname |
+-----+------------+
| 100 | windows |
| 101 | linux |
+-----+------------+
6.8 唯一性约束(UNIQUE)
作用:保证某列的值不能重复。一张表只能有一个主键,但可以设置多个唯一键。
主键与唯一键的关系:
- 主键更多用于标识 一行数据,唯一键更多用于业务唯一性;
- 主键只能有一个,唯一键可以有多个;
- 主键不能为空,唯一键可以为空(且允许多个 NULL);
- 二者是补充关系,可以同时存在;
- 例如学生表:身份证号做主键,学号做唯一键。
sql
mysql> CREATE TABLE t4(
-> id INT PRIMARY KEY,
-> name VARCHAR(20) UNIQUE COMMENT '名字不能重名,可以为空');
mysql> INSERT INTO t4 VALUES (1, '刘文');
mysql> INSERT INTO t4 VALUES (2, '刘文');
ERROR 1062 (23000): Duplicate entry '刘文' for key 't4.name'
唯一键冲突会导致自增字段不连续:
sql
mysql> ALTER TABLE t4 MODIFY id INT AUTO_INCREMENT;
mysql> INSERT INTO t4(name) VALUES ('张磊磊');
mysql> INSERT INTO t4(name) VALUES ('张磊磊'); -- 冲突失败,但自增值已消耗
ERROR 1062 (23000): Duplicate entry '张磊磊' for key 't4.name'
mysql> INSERT INTO t4(name) VALUES ('钱明');
mysql> SELECT * FROM t4;
+----+-----------+
| id | name |
+----+-----------+
| 1 | 刘文 |
| 2 | 张磊 |
| 3 | 张磊磊 |
| 5 | 钱明 | # 4 被失败的那次占用,故不连续
+----+-----------+
6.9 外键约束(FOREIGN KEY)
作用:限定某表的某字段引用另一张表的字段,保证引用完整性。
概念:
- 主表(父表):被引用的表;
- 从表(子表):引用别人的表;
- 外键:从表中的字段引用主表的主键或唯一键;
- 引用键:主表被引用的字段。
要求:
- 主表必须已存在(或自参照);
- 主表被引用列必须有主键或唯一键约束;
- 外键列的数据类型必须与主表对应列一致;
- 外键列可以为
NULL(表示暂未关联); - 外键列数据必须在主表中存在,或为
NULL。
语法:
sql
FOREIGN KEY (从表字段) REFERENCES 主表名(主表字段)
示例:
sql
-- 主表:班级表
mysql> CREATE TABLE myclass3(id INT PRIMARY KEY, name VARCHAR(20) NOT NULL);
-- 从表:学生表,class_id 引用 myclass3.id
mysql> CREATE TABLE myclass3_stu(
-> id INT PRIMARY KEY,
-> name VARCHAR(30) NOT NULL,
-> class_id INT,
-> FOREIGN KEY (class_id) REFERENCES myclass3(id));
mysql> DESC myclass3_stu;
+----------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+----------+-------------+------+-----+---------+-------+
| id | int | NO | PRI | NULL | |
| name | varchar(30) | NO | | NULL | |
| class_id | int | YES | MUL | NULL | |
+----------+-------------+------+-----+---------+-------+
mysql> INSERT INTO myclass3 VALUES (10, 'C++'), (20, 'Java');
mysql> INSERT INTO myclass3_stu VALUES (1, 'Li', 10), (2, 'Sun', 20); -- 正常
mysql> INSERT INTO myclass3_stu VALUES (3, 'wang', 30); -- 主表无 30 号班级
ERROR 1452 (23000): Cannot add or update a child row: a foreign key constraint fails
(`stu_info`.`myclass3_stu`, CONSTRAINT `myclass3_stu_ibfk_1` FOREIGN KEY (`class_id`)
REFERENCES `myclass3` (`id`))
mysql> INSERT INTO myclass3_stu VALUES (3, 'wang', NULL); -- 外键允许 NULL
Query OK, 1 row affected (0.00 sec)
删除主表被引用的数据时,若从表仍有引用会失败;需要先处理从表数据(或建表时使用 ON DELETE CASCADE 等级联策略,生产环境慎用)。
6.10 检查约束(CHECK)
作用:检查字段值是否满足指定条件,一般用于限定取值范围。
注意:MySQL 8.0.16 之前 CHECK 只是语法上接受但不强制执行;8.0.16 起正式支持。
sql
mysql> CREATE TABLE t5(
-> id INT PRIMARY KEY,
-> name VARCHAR(20),
-> salary FLOAT,
-> CHECK(salary > 0 AND salary < 10000));
mysql> INSERT INTO t5 VALUES (1, 'Li', 5984);
Query OK, 1 row affected (0.00 sec)
mysql> INSERT INTO t5 VALUES (2, 'wang', 12000);
ERROR 3819 (HY000): Check constraint 't5_chk_1' is violated.
-- 建表后追加检查约束
mysql> ALTER TABLE t5 ADD CONSTRAINT check_id CHECK(id > 0);
6.11 删除约束速查
| 约束 | 定义级别 | 删除方式 |
|---|---|---|
NOT NULL |
仅列级 | ALTER TABLE 表名 MODIFY 列名 类型; |
DEFAULT |
仅列级 | ALTER TABLE 表名 MODIFY 列名 类型; |
AUTO_INCREMENT |
列属性 | ALTER TABLE 表名 MODIFY 列名 类型; |
PRIMARY KEY |
列级 / 表级 | ALTER TABLE 表名 DROP PRIMARY KEY; |
UNIQUE |
列级 / 表级 | ALTER TABLE 表名 DROP INDEX 唯一约束名; |
FOREIGN KEY |
列级 / 表级 | ALTER TABLE 表名 DROP FOREIGN KEY 外键名; |
CHECK |
列级 / 表级 | ALTER TABLE 表名 DROP CHECK 约束名; |
七、存储引擎与完整建表语句
7.1 什么是存储引擎
存储引擎是数据库底层软件组织,DBMS 使用存储引擎进行创建、查询、更新和删除数据。不同引擎提供不同的存储机制、索引技巧和锁定水平。MySQL 的核心就是插件式存储引擎,可按需选择是否支持事务、使用哪种索引等。
常见存储引擎:
| 引擎 | 特点 | 适用场景 |
|---|---|---|
InnoDB |
支持 ACID 事务、行级锁、外键,MySQL 5.5 之后的默认引擎 | 事务完整性、并发一致性要求高的场景 |
MyISAM |
5.5 之前的默认引擎,插入/查询速度快,不支持事务,表级锁 | 以读写为主、极少更新删除、对事务要求不高的场景 |
MEMORY |
数据全放内存,速度极快,重启后数据丢失 | 临时表、缓存类数据 |
Archive |
高压缩比,插入快,查询支持差 | 历史归档数据 |
CSV |
以 CSV 文本存储,不支持索引 | 数据交换 |
BlackHole |
写入即丢弃,可记录 binlog | 复制中继 |
Federated |
联合不同 MySQL 服务器 | 分布式应用 |
7.2 引擎对比
| 功能 | MyISAM | MEMORY | InnoDB |
|---|---|---|---|
| 存储限制 | 256TB | RAM | 64TB |
| 支持事务 | No | No | Yes |
| 支持全文索引 | Yes | No | No |
| 支持 B 树索引 | Yes | Yes | Yes |
| 支持哈希索引 | No | Yes | No |
| 支持外键 | No | No | Yes |
| 空间使用率 | 低 | N/A | 高 |
7.3 查看与指定存储引擎
sql
SHOW ENGINES \G; -- 查看支持的引擎
SHOW VARIABLES LIKE '%storage_engine%'; -- 查看默认引擎
sql
mysql> SHOW VARIABLES LIKE '%storage_engine%';
+---------------------------------+----------+
| Variable_name | Value |
+---------------------------------+----------+
| default_storage_engine | InnoDB |
| default_tmp_storage_engine | InnoDB |
| disabled_storage_engines | |
| internal_tmp_mem_storage_engine | TempTable|
+---------------------------------+----------+
创建表时指定引擎与字符集:
sql
CREATE TABLE 表名 (...) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
不指定时使用
my.cnf中default-storage-engine=InnoDB配置的默认引擎。
7.4 完整建表语句模板
sql
CREATE TABLE 表名 (
列名 列类型 [AUTO_INCREMENT] [DEFAULT 默认值] [列约束] [COMMENT '说明'],
...
[表级约束]
) [ENGINE=存储引擎] [DEFAULT] CHARSET=字符集;
各选项含义:
| 选项 | 说明 |
|---|---|
| 列类型 | 该列数据的存储类型 |
AUTO_INCREMENT |
自动增长,只能用于数值类型的列 |
DEFAULT |
该列的默认值 |
| 约束 | 对列的限制(非空、唯一、主键、外键、检查) |
ENGINE |
表的存储引擎 |
CHARSET |
表的字符集 |
八、数据库账户与权限管理
8.1 MySQL 8 密码策略
MySQL 8.0 开始,默认身份验证插件由 mysql_native_password 改为 caching_sha2_password。
mysql_native_password依赖 SHA1,而 NIST 已建议停止使用 SHA1(易被破解);caching_sha2_password使用 SHA-256,更安全,是 8.0 的默认插件。
查看密码相关配置:
sql
SHOW VARIABLES LIKE '%password%';
常用参数:
| 参数 | 含义 |
|---|---|
default_password_lifetime |
密码过期时间(天),0 表示永不过期 |
password_history |
不允许使用最近 n 次用过的密码 |
password_reuse_interval |
不允许使用最近 n 天内用过的密码 |
password_require_current |
修改密码时是否需要提供当前密码 |
caching_sha2_password_digest_rounds |
哈希回合数 |
查看密码强度插件策略:
sql
mysql> SHOW VARIABLES LIKE 'validate_password%';
Empty set (0.01 sec) # 为空说明未安装插件
mysql> INSTALL COMPONENT 'file://component_validate_password';
Query OK, 0 rows affected (0.01 sec)
mysql> SHOW VARIABLES LIKE 'validate_password%';
+--------------------------------------+--------+
| Variable_name | Value |
+--------------------------------------+--------+
| validate_password.check_user_name | ON |
| validate_password.dictionary_file | |
| validate_password.length | 8 |
| validate_password.mixed_case_count | 1 |
| validate_password.number_count | 1 |
| validate_password.policy | MEDIUM |
| validate_password.special_char_count | 1 |
+--------------------------------------+--------+
密码强度等级(validate_password.policy):
| 等级 | 检查内容 |
|---|---|
0 / LOW |
仅检查长度 |
1 / MEDIUM |
长度、数字、大小写、特殊字符 |
2 / STRONG |
长度、数字、大小写、特殊字符、字典文件 |
修改策略(临时生效,重启服务后失效):
sql
mysql> SET GLOBAL validate_password.policy = LOW;
mysql> SET GLOBAL validate_password.mixed_case_count = 0;
mysql> SET GLOBAL validate_password.number_count = 6;
mysql> SET GLOBAL validate_password.special_char_count = 0;
mysql> SET GLOBAL validate_password.length = 6;
mysql> FLUSH PRIVILEGES;
永久生效需写入配置文件 /etc/my.cnf:
ini
validate_password.policy=low
validate_password.length=6
validate_password.mixed_case_count=0
validate_password.number_count=6
validate_password.special_char_count=0
修改密码:
sql
ALTER USER 'root'@'localhost' IDENTIFIED BY '新密码';
FLUSH PRIVILEGES;
8.2 登录账户管理原则
MySQL 8 的账户权限管理原则:先创建账户,再赋予权限 。用户信息存放在 mysql 库的 user 表中。
sql
mysql> USE mysql;
mysql> SELECT user, host, plugin FROM mysql.user;
mysql> DESC user;
mysql> SELECT user, host, authentication_string FROM user;
8.3 新建登录账户
sql
CREATE USER '用户名'@'主机' IDENTIFIED BY '密码';
| 参数 | 含义 |
|---|---|
用户名 |
创建的用户名 |
主机 |
允许登录的来源:localhost 表示本机,% 表示任意远程主机 |
密码 |
登录密码,需符合密码策略 |
sql
mysql> CREATE USER 'test1'@'localhost' IDENTIFIED BY '123456';
Query OK, 0 rows affected (0.01 sec)
mysql> SELECT user, host, plugin FROM mysql.user;
mysql> exit
Bye
[root@server ~]# mysql -u test1 -p
Enter password:
注意:
%允许任意 IP 登录,生产环境严禁给 root 配置%。
8.4 账户授权
赋权原则:
- root 账号禁止 允许任意 IP 访问(不能用
%); - 应用账号与管理账号分离;
- 赋权最小化,一般只给
SELECT,尽量不给UPDATE、INSERT、DELETE; - 密码设置合理;
- 定期清理不使用的账户。
常见权限:
| 权限 | 说明 | 级别 |
|---|---|---|
CREATE |
创建数据库、表、索引 | 库/表/索引 |
DROP |
删除数据库、表 | 库/表 |
ALTER |
修改表 | 表 |
INSERT |
添加表数据 | 表 |
SELECT |
查询表数据 | 表 |
UPDATE |
更新表数据 | 表 |
DELETE |
删除表数据 | 表 |
INDEX |
操作索引 | 表 |
REFERENCES |
引用权限 | 库/表 |
GRANT OPTION |
赋予权限 | 库/表 |
CREATE VIEW / SHOW VIEW |
创建/查看视图 | 视图 |
CREATE ROUTINE / ALTER ROUTINE / EXECUTE |
存储过程相关 | 存储过程 |
FILE |
访问服务器文件 | 文件管理 |
CREATE USER |
创建用户 | 服务器管理 |
SHUTDOWN |
关闭数据库 | 服务器管理 |
PROCESS |
查看进程 | 服务器管理 |
SUPER |
超级权限 | 服务器管理 |
ALL [PRIVILEGES] |
所有权限 | --- |
USAGE |
无任何权限(仅能连接) | --- |
查看权限:
sql
mysql> SHOW GRANTS; -- 查看当前账户权限
mysql> SHOW GRANTS FOR 'test1'@'localhost'; -- 查看指定账户权限
+-------------------------------------------+
| Grants for test1@localhost |
+-------------------------------------------+
| GRANT USAGE ON *.* TO `test1`@`localhost` |
+-------------------------------------------+
赋权语法:
sql
GRANT 权限列表 ON 数据库名.表名 TO '用户名'@'来源地址' [IDENTIFIED BY '密码'];
- 权限列表:
SELECT、INSERT、UPDATE、CREATE等,多个用逗号分隔,全部用ALL; - 数据库名:
*代表所有数据库; - 表名:
*代表所有表; - 来源地址:
localhost本机,%任意主机。
示例 1:创建 test1 并赋查询权限
sql
mysql> GRANT SELECT ON *.* TO 'test1'@'localhost';
Query OK, 0 rows affected (0.01 sec)
mysql> SHOW GRANTS FOR 'test1'@'localhost';
+--------------------------------------------+
| Grants for test1@localhost |
+--------------------------------------------+
| GRANT SELECT ON *.* TO `test1`@`localhost` |
+--------------------------------------------+
示例 2:test2 仅允许 172.16.50.0/24 网段登录,赋 SELECT、CREATE
sql
mysql> CREATE USER 'test2'@'10.100.170.%' IDENTIFIED BY '123456';
mysql> GRANT SELECT, CREATE ON *.* TO 'test2'@'10.100.170.%';
mysql> SHOW GRANTS FOR 'test2'@'10.100.170.%';
示例 3:test3 拥有所有权限,可创建 test4 并赋权
sql
mysql> CREATE USER 'test3'@'%' IDENTIFIED BY '123456';
mysql> GRANT ALL ON *.* TO 'test3'@'%';
-- 注意:ALL 不包含「给其他账户赋权」的权限
mysql> GRANT ALL ON *.* TO 'test3'@'%' WITH GRANT OPTION;
8.5 回收权限
sql
REVOKE 权限列表 | ALL ON 库名.表名 FROM '用户名'@'来源地址';
REVOKE 与 GRANT 语法基本一致,只需把 TO 换成 FROM。
sql
mysql> REVOKE SELECT ON *.* FROM 'test4'@'%';
mysql> REVOKE ALL ON *.* FROM 'test3'@'%';
mysql> SHOW GRANTS FOR 'test4'@'%';
8.6 删除账户
sql
DROP USER '用户名'@'访问主机名';
mysql> DROP USER 'test1'@'localhost';
mysql> DROP USER 'test2'@'10.100.170.%';
mysql> DROP USER test3; -- 主机为 % 时可省略主机部分
sql
mysql> SELECT user, host FROM mysql.user;
+------------------+-----------+
| user | host |
+------------------+-----------+
| mysql.infoschema | localhost |
| mysql.session | localhost |
| mysql.sys | localhost |
| root | localhost |
+------------------+-----------+
九、综合练习
9.1 数据库基础练习
创建 temp1、temp2 两个数据库,查看所有数据库,使用 temp1,最后删除 temp1、temp2:
sql
CREATE DATABASE temp1;
CREATE DATABASE temp2;
SHOW DATABASES;
USE temp1;
SELECT DATABASE();
DROP DATABASE temp1;
DROP DATABASE temp2;
9.2 建表练习:班级表
在 mydb2_stuinfo 中新建班级表 class1:
sql
mysql> USE mydb2_stuinfo;
mysql> CREATE TABLE class1(
-> cla_num INT,
-> cla_name VARCHAR(10),
-> number INT,
-> monitor VARCHAR(20),
-> creation_date DATE);
Query OK, 0 rows affected (0.02 sec)
mysql> DESC class1;
9.3 约束综合练习:销售系统
创建销售数据库 mydb5_sales,建产品表与订单表:
sql
mysql> CREATE DATABASE mydb5_sales;
mysql> USE mydb5_sales;
-- 产品表:编号唯一键、名称非空、单价非空、规格默认「件」
mysql> CREATE TABLE pro_tb(
-> pro_num INT UNIQUE,
-> pro_name VARCHAR(30) NOT NULL,
-> pro_price FLOAT(5,2) NOT NULL,
-> pro_spe VARCHAR(8) DEFAULT '件');
Query OK, 0 rows affected, 2 warnings (0.01 sec)
-- 订单表:订单号主键自增、金额检查 > 0、产品编号外键
mysql> CREATE TABLE orders(
-> id INT PRIMARY KEY AUTO_INCREMENT,
-> customer_id INT NOT NULL,
-> pro_num INT NOT NULL,
-> signing_date DATE,
-> amount FLOAT(5,2),
-> CHECK(amount > 0),
-> FOREIGN KEY(pro_num) REFERENCES pro_tb(pro_num));
Query OK, 0 rows affected, 4 warnings (0.02 sec)
mysql> DESC pro_tb;
+-----------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-----------+-------------+------+-----+---------+-------+
| pro_num | int | YES | UNI | NULL | |
| pro_name | varchar(30) | NO | | NULL | |
| pro_price | float(5,2) | NO | | NULL | |
| pro_spe | varchar(8) | YES | | 件 | |
+-----------+-------------+------+-----+---------+-------+
mysql> DESC orders;
+--------------+------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+--------------+------------+------+-----+---------+----------------+
| id | int | NO | PRI | NULL | auto_increment |
| customer_id | int | NO | | NULL | |
| pro_num | int | NO | MUL | NULL | |
| signing_date | date | YES | | NULL | |
| amount | float(5,2) | YES | | NULL | |
+--------------+------------+------+-----+---------+----------------+
9.4 用户授权练习
- 创建
test1@localhost,赋予SELECT权限;用 test1 登录验证只能看到部分库; - 创建
test2@10.100.170.%,赋予SELECT、CREATE,验证可建库; - 创建
test3@%,赋予ALL+WITH GRANT OPTION,验证可创建 test4 并赋权; - 回收 test1~test4 的权限,最后删除这些账户。
sql
-- 回收
REVOKE ALL ON *.* FROM 'test1'@'localhost';
REVOKE ALL ON *.* FROM 'test2'@'10.100.170.%';
REVOKE ALL ON *.* FROM 'test3'@'%';
REVOKE ALL ON *.* FROM 'test4'@'%';
-- 删除
DROP USER 'test1'@'localhost';
DROP USER 'test2'@'10.100.170.%';
DROP USER test3;
DROP USER test4;
十、常见报错与命令速查
10.1 常见报错
| 报错 | 原因 | 解决 |
|---|---|---|
ERROR 2002 ... mysql.sock |
MySQL 服务未启动 | systemctl start mysqld |
ERROR 1007 ... database exists |
数据库已存在 | 换名字或加 IF NOT EXISTS |
ERROR 1064 ... syntax |
SQL 语法错误,常见于用了关键字 | 检查语法,关键字加反引号 |
No database selected |
没先 USE 数据库 |
先 USE 库名; |
ERROR 1364 ... doesn't have a default value |
非空字段未赋值 | 插入时补上该字段 |
ERROR 1062 ... Duplicate entry |
主键/唯一键重复 | 修改重复值 |
ERROR 1452 ... foreign key constraint fails |
外键引用的主键不存在 | 先插入主表数据 |
ERROR 3819 ... Check constraint is violated |
不满足检查约束 | 调整数据范围 |
10.2 命令速查表
sql
-- ===== 数据库 =====
SHOW DATABASES [LIKE '条件']; -- 查看库
CREATE DATABASE 库名; -- 建库
USE 库名; -- 切换库
SELECT DATABASE(); -- 当前库
DROP DATABASE 库名; -- 删库
-- ===== 表 =====
CREATE TABLE 表名(列名 类型 约束, ...); -- 建表
SHOW TABLES [FROM 库名]; -- 查看表
DESC 表名; -- 查看表结构
SHOW CREATE TABLE 表名\G; -- 查看建表语句
ALTER TABLE 表名 RENAME 新表名; -- 改表名
ALTER TABLE 表名 ADD 列名 类型 [FIRST|AFTER 列]; -- 加列
ALTER TABLE 表名 DROP 列名; -- 删列
ALTER TABLE 表名 CHANGE 旧列 新列 类型; -- 改列名
ALTER TABLE 表名 MODIFY 列名 类型; -- 改列类型
DROP TABLE [IF EXISTS] 表名; -- 删表
-- ===== 约束 =====
ALTER TABLE 表名 ADD PRIMARY KEY(列); -- 主键
ALTER TABLE 表名 DROP PRIMARY KEY; -- 删主键
ALTER TABLE 表名 ADD UNIQUE(列); -- 唯一
ALTER TABLE 表名 ADD FOREIGN KEY(列) REFERENCES 主表(列);
ALTER TABLE 表名 DROP FOREIGN KEY 外键名;
ALTER TABLE 表名 ADD CHECK(条件);
ALTER TABLE 表名 DROP CHECK 约束名;
-- ===== 字符集 =====
SHOW CHARACTER SET [LIKE 'utf%'];
SHOW COLLATION;
SHOW VARIABLES LIKE 'character_set%';
-- ===== 存储引擎 =====
SHOW ENGINES\G;
SHOW VARIABLES LIKE '%storage_engine%';
CREATE TABLE 表名(...) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-- ===== 用户与权限 =====
CREATE USER '用户'@'主机' IDENTIFIED BY '密码';
ALTER USER 'root'@'localhost' IDENTIFIED BY '新密码';
GRANT 权限 ON 库.表 TO '用户'@'主机';
GRANT ALL ON *.* TO '用户'@'%' WITH GRANT OPTION;
REVOKE 权限 ON 库.表 FROM '用户'@'主机';
SHOW GRANTS [FOR '用户'@'主机'];
DROP USER '用户'@'主机';
FLUSH PRIVILEGES;
10.3 总结
- SQL 分类:DDL 管结构、DML 管数据、DCL 管权限、TCL 管事务;
- 数据库操作 :
CREATE / SHOW / USE / SELECT DATABASE() / DROP五板斧; - 字符集 :8.0 默认
utf8mb4,utf8实际是utf8mb3,新项目统一utf8mb4+utf8mb4_0900_ai_ci; - 表操作 :
CREATE / DESC / ALTER / DROP / RENAME,复制表要区分仅结构、结构+数据、仅数据; - 数据类型 :整数选合适宽度、金额用
DECIMAL、定长用CHAR、变长用VARCHAR; - 六大约束:非空、默认值、主键、唯一、外键、检查------建表时就规划好,比事后补约束更重要;
- 用户权限 :先建用户再授权、最小权限原则、root 禁用
%登录、定期回收权限。