1. 数据库基础
1.1 什么是数据库
文件保存数据的缺点:
1) 文件的安全性问题
2) 文件不利于数据查询和管理
3) 文件不利于存储海量数据
4) 文件在程序中控制不方便
数据库:解决文件存储的缺陷,更加高效管理数据;数据库水平是衡量程序员水平的重要指标。
数据库存储介质:磁盘、内存
1.2 主流数据库
1. SQL Server:微软产品,.NET程序员常用,适合中大型项目
2. Oracle:甲骨文,适合大型项目、复杂业务逻辑;并发强,闭源收费
3. MySQL:世界最受欢迎开源数据库,中小型互联网项目;并发性能好
4. PostgreSQL:加州大学伯克利开发,开源免费,商用、科研均可
5. SQLite:轻量级嵌入式数据库,不需要服务进程,占用资源极小,多用于嵌入式设备、移动端
6. H2:Java开发嵌入式数据库,是一个类库,可以直接嵌入Java应用
1.3 MySQL基本使用
1.3.1 MySQL安装
CentOS6.5编译安装MySQL5.6.14
CentOS7 yum安装MariaDB
Windows安装MySQL5.7
1.3.2 连接服务器
mysql -h 127.0.0.1 -P 3306 -u root -p
-h:主机地址,不写默认127.0.0.1本地
-P:端口号,不写默认3306
-u:用户名
-p:密码,回车后输入密码
成功登录提示:Welcome to the MySQL monitor. Commands end with ; or \g.
1.3.3 Windows服务器管理
win+r输入services.msc打开服务管理器,可以停止、暂停、重启MySQL服务。
1.3.4 服务器、数据库、表关系
1. 数据库服务器:安装MySQL,是一套管理程序,一台服务器可以管理多个数据库。
2. 数据库(DB):一个项目一般对应一个数据库。
3. 表(Table):一个数据库里面有多张表,保存实体数据。
4. 层级:Client客户端 → MySQL服务 → 多个数据库DB → 每个DB多张表
5. 表:行(记录)、列(字段)。
1.3.5 使用案例
- -- 创建数据库
- create database helloworld;
- -- 使用数据库
- use helloworld;
- -- 创建表
- create table student(
- id int,
- name varchar(32),
- gender varchar(2)
- );
- -- 插入数据
- insert into student (id,name,gender) values (1,'张三','男');
- insert into student (id,name,gender) values (2,'李四','女');
- insert into student (id,name,gender) values (3,'王五','男');
- -- 查询全部数据
- select * from student;
复制代码
1.3.6 数据逻辑存储
行row:一条完整记录
列column:字段,代表属性
1.4 MySQL架构
MySQL跨平台:支持Linux、Windows、MacOS。
分层:
1. Client Connectors:各种语言驱动(JDBC、PHP、Python等)
2. Connection Pool:连接池、权限认证、安全
3. SQL Interface:SQL接口接收语句
4. Parser:语法解析器,词法语法分析
5. Optimizer:查询优化器,生成最优执行计划
6. Caches:查询缓存
7. Pluggable Storage Engines 可插拔存储引擎:真正负责读写数据
InnoDB、MyISAM、Memory、Archive等
8. File System:底层磁盘文件系统;日志文件(redo、undo、binary log等)
1.5 SQL语句分类
| 分类 | 全称 | 作用 | 关键字 |
| DDL | Data Definition Language | 数据定义语言,定义库、表结构 | create、drop、alter |
| DML | Data Manipulation Language | 数据操纵语言,操作表里数据 | insert、delete、update |
| DQL | Data Query Language | 数据查询语言(DML拆分出来) | select |
| DCL | Data Control Language | 数据控制语言,权限、事务 | grant、revoke、commit |
1.6 存储引擎
1.6.1 概念
存储引擎:MySQL如何存储数据、建立索引、更新查询数据的底层实现方式。MySQL支持可插拔多种存储引擎。
1.6.2 查看存储引擎
1.6.3 常用引擎对比
1. InnoDB(MySQL8.0默认)
✅支持事务、行锁、外键、MVCC
适合增删改频繁业务,互联网项目首选
2. MyISAM
❌不支持事务;表锁;查询速度快;支持全文索引
适合大量查询,很少修改场景,崩溃丢失数据
3. Memory
全部数据放内存,断电丢失,速度极快
4. Archive:只支持插入查询,压缩存储
5. NDB:集群引擎
2. 库的操作
2.1 创建数据库
语法:
- CREATE DATABASE [IF NOT EXISTS] db_name
- [DEFAULT CHARACTER SET charset_name]
- [DEFAULT COLLATE collation_name];
复制代码
IF NOT EXISTS:数据库不存在才创建,防止报错
CHARACTER SET(charset):字符集
COLLATE:排序/校验规则
2.2 案例
- --最简创建
- create database db1;
- --指定字符集
- create database db2 charset=utf8;
- --字符集+collate
- create database db3 charset=utf8 collate utf8_general_ci;
复制代码
不指定字符集collate,使用MySQL服务器默认。
| 项目 | charset(字符集) | collate(排序规则) |
| 核心作用 | 定义字符的二进制存储编码 | 定义字符串比较、排序的规则 |
| 解决问题 | 这个字怎么存到数据库?字节是什么? | 'A'和'a'算不算相等?查询、order by怎么排? |
| 示例值 | utf8mb4、utf8、latin1 | utf8mb4_general_ci、utf8mb4_bin |
| 从属关系 | 一个charset可以对应多个collate | collate必须依附某个charset,不能单独存在 |
2.3 字符集和校验规则collate
2.3.1 查看数据库字符集、排序规则
- show variables like 'character_set_database';
- show variables like 'collation_database';
复制代码
2.3.2 查看全部支持字符集
2.3.3 查看全部collate排序规则
2.3.4 collate对查询、排序的影响
1. utf8_general_ci:ci=case insensitive大小写不敏感
- create database test1 collate utf8_general_ci;
- use test1;
- create table person(name varchar(20));
- insert into person values('a'),('A'),('b'),('B');
- select * from person where name='a';
- -- 结果:a 和 A 两条都会查出来,大小写视为相等
复制代码
2. utf8_bin:二进制比较,区分大小写
- create database test2 collate utf8_bin;
- use test2;
- create table person(name varchar(20));
- insert into person values('a'),('A'),('b'),('B');
- select * from person where name='a';
- --只会匹配'a',不会匹配'A'
复制代码
order by排序也会受collate影响,ci不区分大小写排序,bin严格二进制排序。
2.4 操纵数据库
2.4.1 查看服务器所有数据库
2.4.2 查看数据库创建语句
- show create database 数据库名;
复制代码
反引号 ` 包裹库名,防止库名和关键字冲突。
/*!40100 ... */:版本条件注释,高版本MySQL才执行。
2.4.3 修改数据库
只能修改字符集、collate;不能修改数据库名字
- ALTER DATABASE db_name
- [DEFAULT CHARACTER SET charset_name]
- [DEFAULT COLLATE collation_name];
复制代码
示例: alter database mytest charset=gbk;
⚠️只修改数据库设置,不会自动修改已经存在的表。
2.4.4 删除数据库
- DROP DATABASE [IF EXISTS] db_name;
复制代码
IF EXISTS:存在才删除,避免报错
删除效果:数据库消失;对应磁盘文件夹被删除;库里面所有表全部级联删除
⚠️禁止随意删除数据库!
2.4.5 备份与恢复(mysqldump)
mysqldump是外部命令,退出mysql终端执行,不是sql语句。
备份整个数据库
- mysqldump -P3306 -u root -p -B 数据库名 > 备份文件.sql
复制代码
示例:mysqldump -P3306 -u root -p123456 -B mytest > D:/mytest.sql
导出的.sql里面保存全部建库、建表、插入数据SQL。
恢复(source命令,mysql内部执行)
- source D:/mysql-5.7.22/mytest.sql;
复制代码
其他备份用法
1. 只备份库中几张表,不带-B
- mysqldump -u root -p 库名 表1 表2 > xxx.sql
复制代码
2. 同时备份多个数据库
- mysqldump -u root -p -B db1 db2 > all.sql
复制代码
不带-B参数备份:恢复前要手动先create database,use数据库再source。
2.4.6 查看数据库连接
作用:
1. 查看当前哪些用户正在连接MySQL
2. 发现陌生连接,判断是否被入侵
3. 数据库慢的时候,可以看连接状态定位问题
输出字段:Id、User、Host、db、Command、Time、State、Info
考试高频易错总结
1. charset字符集:管文字怎么存;collate排序规则:管字符串比较、where匹配、order by排序。
2. ci大小写不敏感;bin二进制区分大小写。
3. 修改数据库charset/collate不会更新已有表。
4. InnoDB支持事务、行锁;MyISAM表锁,不支持事务。
5. mysqldump是shell命令,不是mysql内部sql;source是mysql内部恢复命令。
6. DDL定义结构(create/drop/alter),DML操作数据(insert/update/delete),DQL查询select。
7. 删除数据库drop database级联删除全部表,谨慎操作。
8. MySQL的utf8不是完整utf‑8,最多3字节,不能存emoji,生产优先utf8mb4。
3. 表的操作
3.1 创建表
语法
- CREATE TABLE table_name (
- field1 datatype,
- field2 datatype,
- field3 datatype
- ) character set 字符集 collate 校验规则 engine 存储引擎;
复制代码
参数说明
field:表的列名
datatype:列的数据类型
character set:字符集,不指定则继承数据库字符集
collate:校验规则,不指定则继承数据库校验规则
engine:指定存储引擎
3.2 创建表案例
- create table users (
- id int,
- name varchar(20) comment '用户名',
- password char(32) comment '密码是32位的md5值',
- birthday date comment '生日'
- ) character set utf8 engine MyISAM;
复制代码
💡 MyISAM存储引擎文件说明:
使用MyISAM引擎建表,磁盘会生成3个文件:
1) users.frm:表结构文件
2) users.MYD:表数据文件
3) users.MYI:表索引文件
对比:InnoDB引擎只有 .frm 和 .ibd 文件,数据和索引放在ibd文件中。
3.3 查看表结构
语法
示例
输出字段含义:
| 字段 | 含义 |
| Field | 字段名字 |
| Type | 字段类型 |
| Null | 是否允许为空 |
| Key | 索引类型 |
| Default | 默认值 |
| Extra | 扩充属性 |
3.4 修改表 ALTER TABLE
开发中经常需要新增字段、修改字段类型、删除字段、重命名表、重命名字段。
核心语法
- -- 添加字段
- ALTER TABLE tablename ADD (column datatype [DEFAULT expr][,column datatype]...);
- -- 修改字段类型/长度
- ALTER TABLE tablename MODIFY (column datatype [DEFAULT expr][,column datatype]...);
- -- 删除字段
- ALTER TABLE tablename DROP (column);
- -- 修改表名
- ALTER TABLE old_table RENAME [TO] new_table;
- -- 修改列名(必须完整重写类型)
- ALTER TABLE 表名 CHANGE 旧列名 新列名 数据类型;
复制代码
实操案例
1. 插入测试数据
- insert into users values(1,'a','b','1982-01-04'),(2,'b','c','1984-01-04');
复制代码
2. 新增字段,在birthday后面增加图片路径字段
- alter table users add assets varchar(100) comment '图片路径' after birthday;
复制代码
新增字段不会影响原有数据,旧数据新增字段处值为NULL。
3. 修改字段长度,把name长度改为60
- alter table users modify name varchar(60);
复制代码
4. 删除字段 ⚠️危险,字段和对应数据全部丢失
- alter table users drop password;
复制代码
5. 修改表名
- alter table users rename to employee;
复制代码
to关键字可以省略。
6. 修改列名
CHANGE语法:新字段必须完整定义,不能只写名字
- alter table employee change name xingming varchar(60);
复制代码
3.5 删除表
语法
- DROP [TEMPORARY] TABLE [IF EXISTS] tbl_name [, tbl_name] ...
复制代码
IF EXISTS:如果表不存在不会报错,推荐写在生产脚本
TEMPORARY:只删除临时表
示例:
📌面试重点总结
1. MyISAM 3个文件:.frm结构、.MYD数据、.MYI索引;InnoDB:.frm、.ibd
2. modify:改字段类型长度;change:改列名(必须重写类型)
3. add ... after 列名:控制新增字段位置
4. drop删除字段,数据直接丢失,不可恢复
5. 删除表建议带上if exists,避免脚本执行报错
4. 数据类型
4.1 数据类型总览
| 分类 | 类型 | 说明 |
| 数值类型 | BIT(M) | 位类型,M位数1‑64 |
| TINYINT [UNSIGNED] | 1字节,很小整数 |
| SMALLINT [UNSIGNED] | 2字节 |
| INT [UNSIGNED] | 4字节,最常用 |
| BIGINT [UNSIGNED] | 8字节,大整数 |
| FLOAT(M,D) | 单精度浮点数 |
| DOUBLE(M,D) | 双精度浮点数 |
| DECIMAL(M,D) | 定点数,高精度,财务推荐 |
| 文本二进制 | CHAR(size) | 定长字符串 |
| VARCHAR(size) | 可变长字符串 |
| BLOB | 二进制原始数据 |
| TEXT | 大文本 |
| 时间日期 | DATE | 日期 yyyy‑mm‑dd |
| DATETIME | 日期时间 yyyy‑mm‑dd hh:mm:ss |
| TIMESTAMP | 时间戳,4字节,自动更新 |
| 字符串枚举 | ENUM | 单选枚举 |
| SET | 多选集合 |
4.2 数值类型
整数范围表
| 类型 | 字节 | 有符号最小值 | 有符号最大值 | 无符号最小值 | 无符号最大值 |
| 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 |
默认是有符号;加上UNSIGNED变成无符号,只能存非负数。
⚠️生产建议:尽量少用UNSIGNED,数据存不下直接升级为BIGINT。
TINYINT越界测试
- create table tt1(num tinyint);
- insert into tt1 values(1);
- insert into tt1 values(128); --越界报错 Out of range
复制代码
无符号示例
- create table tt2(num tinyint unsigned);
- insert into tt2 values(-1); --报错,不能负数
- insert into tt2 values(255); --合法
复制代码
4.2.1 BIT位类型
语法:bit(M),M范围1‑64,默认M=1
select查询bit,默认显示ASCII字符,不直接显示数字。适合存储0/1状态。
- create table tt4(id int, a bit(8));
- insert into tt4 values(10,10);
- select * from tt4; --bit字段显示字符,看不到数字10
- --bit(1)只存0或1,节省空间,性别、开关状态
- create table tt5(gender bit(1));
- insert into tt5 values(0);
- insert into tt5 values(1);
- insert into tt5 values(2); --越界报错
复制代码
4.2.2 小数类型
FLOAT
语法:float(M,D) [unsigned]
M总显示长度,D小数位数,占用4字节;会四舍五入,精度大约7位,不适合财务。
float(4,2):范围 -99.99 ~ 99.99;unsigned则0‑99.99
- create table tt6(id int, salary float(4,2));
- insert into tt6 values(100,-99.99);
- insert into tt6 values(101,-99.991); --四舍五入保存-99.99
复制代码
DECIMAL(定点数,财务必用)
语法:decimal(M,D) [unsigned]
高精度,不会丢失精度,金额、账单必须用decimal。
decimal(5,2):总长度5位,小数占2位,范围 -999.99 ~999.99
decimal 整数最大位数M为65,支持小数最大位数D为30。如果D被省略,默认为0。如果M被省略,默认为10。
- create table tt8(
- id int,
- salary float(10,8),
- salary2 decimal(10,8)
- );
- insert into tt8 values(100,23.12345612, 23.12345612);
- --float会丢失精度,decimal保持准确
复制代码
float:近似存储;decimal:精确存储。涉及钱一定用decimal!
4.3 字符串类型 char vs varchar
CHAR(L) 定长字符串
• 固定长度,L最多255个字符
• 数据不足L长度,内存仍然占满L;查询速度快,浪费空间。
适合:身份证、手机号、md5密码,长度固定数据。
- create table tt9(id int,name char(2));
- insert into tt9 values(100,'ab');
- insert into tt9 values(101,'中国');
复制代码
VARCHAR(L) 可变长字符串
• L:最多字符数,实际字节受字符集限制,最大长度65535个字节,utf8一个汉字占3字节。
• 按需占用空间,节省存储,性能略低于char。
适合:姓名、地址,长度变化的数据。
- create table tt10(id int,name varchar(6));
- insert into tt10 values(100,'hello');
- insert into tt10 values(100,'我爱你,中国');
复制代码
char与varchar对比总结
| 情况 | char(4) | varchar(4) |
| 存储abcd | 占4字符 | 占4+1字节 |
| 存储A | 占4字符 | 占1+1字节 |
✅选型:
1. 长度固定 → char(手机号、md5)效率高,浪费空间无所谓
2. 长度变化大 → varchar,节省磁盘
3. char最大255字符;varchar最大受行大小限制。
4.4 日期时间类型
| 类型 | 字节 | 格式 | 说明 |
| DATE | 3 | yyyy‑mm‑dd | 只存日期 |
| DATETIME | 8 | yyyy‑mm‑dd hh:mm:ss | 日期+时间,范围1000‑9999年 |
| TIMESTAMP | 4 | yyyy‑mm‑dd hh:mm:ss | 时间戳,插入更新自动填充当前时间,1970起始 |
- create table birthday(t1 date, t2 datetime, t3 timestamp);
- insert into birthday(t1,t2) values('1997‑7‑1','2008‑8‑8 12:1:1');
- --t3 timestamp 不赋值,自动填入当前时间
- update birthday set t1='2000‑1‑1';
- --更新行,timestamp会自动刷新为当前时间
复制代码
业务小提示:只需要日期用date;完整时间用datetime;timestamp会自动更新,适合记录修改时间。
4.5 ENUM 与 SET
ENUM 单选枚举:只能选给定列表其中一个值,底层存储数字。
SET 多选集合:可以选列表中0个、1个或者多个,底层位图存储,最多64个选项。
- set('登山','游泳','篮球','武术');
复制代码
案例:
- create table votes(
- username varchar(30),
- hobby set('登山','游泳','篮球','武术'),
- gender enum('男','女')
- );
- insert into votes values('雷锋','登山,武术','男');
- insert into votes values('Juse','登山,武术',2); --enum数字2代表女
复制代码
⚠️注意:where hobby='登山' 只能匹配只选登山的记录;同时选登山+武术查不出来。
查询集合包含某一项,使用find_in_set()函数!
- --查询爱好包含登山的所有记录
- select * from votes where find_in_set('登山', hobby);
复制代码
find_in_set(sub,str_list):找到返回下标,找不到返回0。
- select find_in_set('a','a,b,c'); --返回1
- select find_in_set('a,b','a,b,c'); --返回0,只能查找一项
- select find_in_set('d','a,b,c'); --返回0
复制代码
📌面试重点总结
1. 整数类型:tinyint(1字节) ~ bigint(8字节),unsigned无符号,不推荐滥用。
2. bit类型查询显示ASCII字符,适合0/1开关。
3. 金额绝对不能用float/double,必须用decimal定点数!
4. char定长,varchar变长;char上限255字符。
5. timestamp会自动更新时间;datetime不会自动。
6. enum单选,set多选;set查询包含某一项要用find_in_set()。
5. 表的约束
作用:数据类型约束比较单一,约束是额外校验规则,从业务逻辑层面保证存入数据库的数据合法、正确。
常见约束:null/not null、default、comment、zerofill、primary key、auto_increment、unique key、foreign key
5.1 空属性 NULL / NOT NULL
知识点
1. NULL:允许为空(系统默认),该字段可以不填数据
2. NOT NULL:不为空,该字段必须填入数据,不能是NULL
3. 运算大坑:NULL参与任何数学运算,结果永远为NULL
- select 1+null; -- 结果为NULL,得不到1
复制代码
4. 开发规范:业务中尽量设置 NOT NULL
原因:空值无法正常参与运算、索引效率差,业务上很多字段本来就不应该为空(班级名、姓名)
示例代码
- -- 创建班级表,班级名称、教室不能为空
- create table myclass(
- class_name varchar(20) not null,
- class_room varchar(10) not null
- );
- -- 查看表结构
- desc myclass;
- -- 报错!缺少class_room,字段不允许为空
- insert into myclass(class_name) values('class1');
- -- ERROR 1364 (HY000): Field 'class_room' doesn't have a default value
复制代码
5.2 默认值 DEFAULT
知识点
1. 默认值:插入数据不给该字段传值时,自动填入预设的默认数据
2. 只有设置了default的字段,插入语句才可以省略该列
3. 如果手动传入数值,优先使用传入的值,不会触发默认值
示例代码
- create table tt10 (
- name varchar(20) not null,
- age tinyint unsigned default 0,
- sex char(2) default '男'
- );
- desc tt10;
- -- 只插入name,age、sex自动使用默认值 0、男
- insert into tt10(name) values('zhangsan');
- select * from tt10;
复制代码
查询结果:
注意:not null 和 default一般不同时写。有默认值,就算不传,字段也不会是空,不需要not null。
5.3 列注释 COMMENT
知识点
1. comment 不影响任何表逻辑,仅用来给字段写中文说明,给开发/DBA阅读
2. desc 表名 看不到注释
3. 使用 show create table 表名\G 才能完整查看 建表语句+注释
示例代码
- create table tt12 (
- name varchar(20) not null comment '姓名',
- age tinyint unsigned default 0 comment '年龄',
- sex char(2) default '男' comment '性别'
- );
- -- 完整查看建表语句,显示注释
- show create table tt12\G
复制代码
5.4 zerofill 零填充
知识点
1. 只作用于数字类型
2. int(5):括号内数字本身没有意义,只有搭配zerofill才生效
3. 功能:查询展示的时候,数字前面补0,补齐到设定长度
⚠重点:只是显示效果!数据库底层存储仍然是原始数字,不会改变存储的值
4. 添加zerofill,字段会自动带上unsigned无符号属性,不能存负数
示例代码
- -- 修改a字段,5位长度,零填充
- alter table tt3 change a int(5) unsigned zerofill;
- insert into tt3 values(1,2);
- select * from tt3;
- -- 查询输出:00001 , 2
- -- 底层存储依旧是数字1,hex(a)验证存储值不变
- select a,hex(a) from tt3;
复制代码
5.5 主键 primary key(PRI)
知识点
1. 主键约束2条硬性规则
✅值不能重复(唯一) ✅不能为NULL(非空)
2. 一张表最多只能有1个主键
3. 主键字段业务首选整数类型,查询、关联性能更好
4. 分类:单字段主键、复合主键(多字段联合主键)
复合主键:多个字段合在一起作为主键,组合整体不能重复,单个字段可以重复
①单主键示例
- -- 创建时直接指定主键
- create table tt13 (
- id int unsigned primary key comment '学号不能为空',
- name varchar(20) not null
- );
- desc tt13;
- -- 重复主键插入直接报错
- insert into tt13 values(1,'aaa');
- insert into tt13 values(1,'aaa');
- -- ERROR 1062 (23000): Duplicate entry '1' for key 'PRIMARY'
- -- 表建好之后追加主键
- alter table 表名 add primary key(字段列表);
- -- 删除主键(不需要写字段名,一张表只有一个主键)
- alter table tt13 drop primary key;
复制代码
②复合主键示例
- create table tt14(
- id int unsigned,
- course char(10) comment '课程代码',
- score tinyint unsigned default 60 comment '成绩',
- primary key(id,course) -- id+课程 联合复合主键
- );
- desc tt14;
- insert into tt14 (id,course)values(1,'123');
- -- 组合完全一样,主键冲突报错
- insert into tt14 (id,course)values(1,'123');
复制代码
5.6 自增长 auto_increment
知识点
1. 作用:插入数据不给值,数据库自动生成一个+1递增的整数
2. 强制前提:字段本身必须是索引(一般搭配primary key主键);字段类型必须是整数;一张表最多只能设置1个自增长列
3. 自增规则:从当前表里已有最大ID+1生成新ID
4. 获取刚刚插入的自增ID:select last_insert_id();
批量插入时,返回第一条生成的自增id
示例代码
- create table tt21(
- id int unsigned primary key auto_increment,
- name varchar(10) not null default ''
- );
- -- 不给id,自动自增
- insert into tt21(name) values('a');
- insert into tt21(name) values('b');
- select * from tt21;
- -- id自动变成1,2
- -- 获取上一次自增id
- select last_insert_id();
复制代码
5.7 唯一键 unique key(UNI)
知识点
1. 作用:保证字段业务不重复(手机号、邮箱、身份证)
2. 和主键对比核心区别
| 约束 | 能否NULL | 一张表数量 |
| primary key | ❌不允许为空 | 只能1个 |
| unique key | ✅允许NULL,NULL之间不做重复校验 | 可以多个 |
业务经验:主键用无业务含义自增ID;唯一键用来约束业务字段不能重复(邮箱、身份证)
示例代码
- create table student (
- id char(10) unique comment '学号,不能重复,但可以为空',
- name varchar(10)
- );
- insert into student(id,name) values('01','aaa');
- insert into student(id,name) values('01','bbb'); -- 重复报错
- insert into student(id,name) values(null,'bbb'); -- NULL可以多次插入
- select * from student;
复制代码
5.8 外键 foreign key
知识点
1. 作用:约束两张表的数据关联性,保证从表数据一定在主表存在,杜绝脏数据
主表:被引用的表(班级表)
从表:设置外键的表(学生表)
2. 语法
- foreign key(从表字段) references 主表名(主表主键字段)
复制代码
3. 约束规则
1)从表外键的值,要么等于主表已经存在的值
2)从表外键的值,要么直接为NULL
3)主表被从表引用的数据,不能随意删除
4)主表被引用列,必须是主键或者唯一键
开发提醒:MySQL外键是数据库层校验;大型互联网项目一般不在数据库建立外键,业务代码层面做逻辑校验
示例代码
- -- 1.先建【主表】班级表
- create table myclass (
- id int primary key,
- name varchar(30) not null comment '班级名'
- );
- -- 2.再建【从表】学生表,设置外键关联班级id
- create table stu (
- id int primary key,
- name varchar(30) not null comment '学生名',
- class_id int,
- foreign key (class_id) references myclass(id)
- );
- -- 主表插入班级
- insert into myclass values(10,'C++大牛班'),(20,'java大神班');
- -- 合法,班级10、20主表里存在
- insert into stu values(100,'张三',10),(101,'李四',20);
- -- ❌报错:班级30不存在,外键约束拦截
- insert into stu values(102,'wangwu',30);
- -- ✅合法:外键给NULL,学生暂时没有分配班级
- insert into stu values(102,'wangwu',null);
复制代码
5.9 综合建表案例(商店业务三张表)
业务说明:商品表、客户表、购买订单表,主外键关联约束
需求清单
1.每张表设置主键、自增
2.客户姓名不能为空
3.邮箱不能重复(unique唯一键)
4.性别只能:男 / 女(enum枚举)
- -- 创建数据库
- create database if not exists bit32mall
- default character set utf8 ;
- use bit32mall;
- -- 商品表 goods
- create table if not exists goods
- (
- goods_id int primary key auto_increment comment '商品编号',
- goods_name varchar(32) not null comment '商品名称',
- unitprice int not null default 0 comment '单价,单位分',
- category varchar(12) comment '商品分类',
- provider varchar(64) not null comment '供应商名称'
- );
- -- 客户表 customer
- create table if not exists customer
- (
- customer_id int primary key auto_increment comment '客户编号',
- name varchar(32) not null comment '客户姓名',
- address varchar(256) comment '客户地址',
- email varchar(64) unique key comment '电子邮箱',
- sex enum('男','女') not null comment '性别',
- card_id char(18) unique key comment '身份证'
- );
- -- 购买订单 purchase(从表,双外键)
- create table if not exists purchase
- (
- order_id int primary key auto_increment comment '订单号',
- customer_id int comment '客户编号',
- goods_id int comment '商品编号',
- nums int default 0 comment '购买数量',
- foreign key (customer_id) references customer(customer_id),
- foreign key (goods_id) references goods(goods_id)
- );
复制代码
📌约束面试重点总结
1. not null:字段禁止为空;default不传值自动填充预设内容
2. zerofill:仅查询显示补零,存储数值不变,自动unsigned无符号
3. primary key:主键,非空+唯一,一张表只能1个主键,支持复合主键
4. auto_increment:自增,必须绑定整数索引(主键),单表只能1个
5. unique key:唯一键,可以多个,可以存NULL,只约束业务字段不重复
6. foreign key外键:关联两张表,从表数据必须在主表存在或者NULL,管控数据完整性
7. comment注释仅文档作用,不参与任何校验逻辑