何为约束,根据表的数据内容作出限制,在创建表的时候,确定出来,跟随建表语句,一起设置到数据库服务器中。
1.约束类型:
NOT NULL - 指示某列不能存储 NULL 值。
UNIQUE - 保证某列的每行必须有唯一的值。
DEFAULT - 规定没有给列赋值时的默认值。
PRIMARY KEY - NOT NULL 和 UNIQUE 的结合。确保某列(或两个列多个列的结合)有唯一标
识,有助于更容易更快速地找到表中的一个特定的记录。
FOREIGN KEY - 保证一个表中的数据匹配另一个表中的值的参照完整性。
CHECK - 保证列中的值符合指定的条件。对于MySQL数据库,对CHECK子句进行分析,但是忽略
CHECK子句。
1.1:NOT NULL,UNIQUE,DEFAULT

注意:a.default是Mysql设定的默认值,不需要我们去单独设定;
b.指定列插入时,未指定值是就是默认值default;
c.对于空值null插入时,当插入行是unique,null值不视为重复;
2.主键约束(PRIMARY KEY):
主键约束是数据的一条身份标识,它相当于NOT NULL + UNIQUE;
2.1.语法:
sql
create table student(id int primary key,sn int unique,name varchar(20),qq_email varchar(20));

**注意:**a.如图所示,在Mysql中,unique+not null会被自动转换成primary key;
b.一个表中,只能有一个主键,但一个主键可以包含多个列,这样即构成了联合主键(不建议使用);
2.2自增主键:
自增主键就是给主键字段按顺序生成唯一数字,不需要手动赋值,保证主键不重复,不混乱;
注意:a.只有主键或者唯一键才能用自增操作;
b.必须为数值类型,如int bigint;
c.即使不指定id,Mysql也会根据自增主键自动添加编号;

d.如果中间出现不连续的数据,编译器会根据最后插入的数据进行自增,例如当我在插入id=3的数据后,再偷偷插入id=100,自增主键会根据我最后插入的100进行自增;
**【疑问】:**当数据库被做成分布式的,那么数据库或数据表可能被拆成很多份,分别存储在多个Mysql的机器上,那么此时自增主键无法确保两个机器上的数据都还是唯一的,这是我们应该怎么做?
【解答】:这里我们给出一种方式,雪花算法,这种方式企业常用,保证全局唯一、趋势递增、高性能、无中间件依赖,是分布式系统首选的主键方案;
a.目的:在分布式的环境下,快速生成唯一 ,有序 ,纯数字的ID;
b. 特点:1).生成64位long类型数据;
2).全局唯一;
3).趋势递增,Mysql主键友好;
4).高并发:每秒生成百万级ID。
c.ID结构:一个雪花ID = 64个二进制位
= 一位符号位 + 41位时间戳 + 10位机器ID + 12位序列号;
注意:1).符号位:这里的符号位固定为0(表示ID永远为正数);
2).41位时间戳:单位毫秒,从某个时间开始算,能用69年,保证ID趋势递增;
3).机器ID:例如可以为 5位数据中心 ID +5 位机器 ID ;
4).12位序列号:同一毫秒,同一台机器内生成的自增序号,从0开始,到4095,每毫秒最多生 成4096个ID ,保证高并发下不重复;
d.核心原理:同一毫秒 + 同一机器 + 唯一序列号 = 绝对唯一 ID;
e.流程:
- 获取当前毫秒时间戳
- 如果是同一毫秒,序列号 + 1
- 如果序列号用完(4095),等待到下一毫秒
- 把 符号位 + 时间戳 + 机器 ID + 序列号 拼接成一个数字
3.外键约束(FOREIGN KEY):
用于建立两个表中的关联关系,让一个表的字段引用另一个表的主键,保证数据的完整性,一致性,防止无效数据。
简单来说就是 子表的外键 = 父表的主键,子表不能插入父表中不存在的数据。
3.1语法:
sql
CREATE TABLE 子表 (
字段名 类型,
FOREIGN KEY (子表字段) REFERENCES 父表(主键)
);
举例:
sql
-- 父表创建:
drop table if exists student;
create TABLE classes(id int primary key auto_increment,name varchar(20),`desc` varchar(20));
-- 子表创建:
drop table if exists classes;
create table student(id int primary key auto_increment,name varchar(20) default 'ubknown',qq_email varchar(20),classes_id int,foreign key(classes_id) references classes(id));
3.2:修改数据是否可行?


那么是否可以从父表或者子表修改这两个表的数据呢?答案肯定是不行的,来看上面编译器运行代码的两个报错,核心意思就是外键约束失败,当你想删除/更新父/子表时,另外一个表中仍然有数据在引用他,数据库为了保护数据不混乱,禁止你删除!

sql
-- 父表创建:
drop table if exists student;
create table classes(class_id int primary key auto_increment,class_name varchar(20) default "inknown");
desc student;
-- 子表创建:
drop table if exists classes;
create table student(id int primary key auto_increment,name varchar(20) default 'ubknown',classes_id int,foreign key(classes_id) references classes(class_id));
desc classes;
insert into classes values(null,"java101"),(null,"java102"),(null,"java103");
select * from classes;
insert into student values(null,"张三",1),(null,"李四",2),(null,"王五",3);
insert into student values(null,"赵六",2);
select *from student;
update student set classes_id=100 where id=1;
delete from classes where class_id=1;
3.3:经典面试题:
这里有一个场景,在一个电商网站,存在两张表,一张商品表(父表),一张订单表(子表),那么如果商家想进行商品信息更改,根据前面的知识,肯定不能直接对子表或者父表进行修改,也就是说不能进行物理意义在硬盘上删除,那么此时我们就可以在创建父表时在数据栏加上一列isOk,他表示逻辑删除,1代表存在,0代表已删除,这样就可以解决这个问题了。
4.CHECK约束:
指定一个条件,根据实际需求,灵活定义,check内部可以写各种条件,check从MYSQL8才开始支持,虽然MYSQL5.7使用不会报错,但没有实际效果!
4.1列级约束:创建表时,字段后直接写
sql
CREATE TABLE student (
id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(20),
age INT CHECK (age >= 0), -- 年龄不能小于0
gender CHAR(2) CHECK (gender IN ('男','女')), -- 性别只能男女
score INT CHECK (score BETWEEN 0 AND 100) -- 分数0-100
);
4.2表级约束:创建表时,最后统一写
sql
CREATE TABLE student (
id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(20),
age INT,
score INT,
-- 统一写 CHECK
CHECK (age >= 0),
CHECK (score BETWEEN 0 AND 100)
);
4.3:报错:
违反check会出现这个报错,3819 - Check constraint 'student_chk_1' is violated.原因是插入的值不满足约束条件,数据库拒绝!
本章完。。。。。。
