概念:约束是作用于表中字段上的规则,用于限制存储在表中的数据。目的:保证数据库中数据的正确、有效性和完整性。
| 约束 | 描述 | 关键字 |
|---|---|---|
| 非空约束 | 限制该字段的数据不能为null | NOT NULL |
| 唯一约束 | 保证该字段的所有数据都是唯一、不重复的 | UNIQUE |
| 主键约束 | 主键是一行数据的唯一标识,要求非空且唯一 | PRIMARY KEY |
| 默认约束 | 保存数据时,如果未指定该字段的值,则采用默认值 | DEFAULT |
| 检查约束(8.0.16版本之后) | 保证字段值满足某一个条件 | CHECK |
| 外键约束 | 用来让两张表的数据之间建立连接,保证数据的一致性和完整性 | FOREIGN KEY |
A.创建tb_user 表生成id字段为主键自增,name 不为空,不重复,年龄大于0小于120,状态默认值为1,性别无限制
create table tb_user(
id int AUTO_INCREMENT PRIMARY KEY comment 'ID唯一标识',
name varchar(20) NOT NULL UNIQUE comment '姓名(不为空,不重复)',
age int CHECK ( age > 0 && age < 120 )comment '年龄',
status int DEFAULT '1' comment '状态',
gender char(1) comment '性别'
)
插入值测试验证
insert into tb_user(name,age,status,gender) values
('Tom1',19,'1','男'),
('Tom2',25,'0','男');
insert into tb_user(name,age,status,gender) values
('Tom3',19,'1','男');
insert into tb_user(name,age,status,gender) values (null,19,'1','男');
Column 'name' cannot be null 因为 NOT NULL约束name 不能为空
insert into tb_user(name,age,status,gender) values ('Tom3',19,'1','男');
Duplicate entry 'Tom3' for key 'tb_user.name' 因为name设置了UNIQUE 数据库发现表中已经存在一条 name 为 'Tom3' 的记录,因此拒绝插入这条重复数据
insert into tb_user(name,age,status,gender) values ('Tom5',-1,'1','男');
Check constraint 'tb_user_chk_1' is violated. 违反检查约束
外键约束
外键:用来让两张表的数据之间建立连接,从而保证数据的一致性和完整性。
我们先创建一个tb_game 记录游戏名称 关联 honor_of_kings_hero 角色表 做到角色和游戏关联
-- 创建游戏表
create table tb_game(
id int AUTO_INCREMENT PRIMARY KEY comment 'ID唯一标识',
name varchar(20) NOT NULL UNIQUE comment '游戏名称'
)comment '游戏表';
-- 添加数据
insert into tb_game(name) values ('王者荣耀'),('英雄联盟');
-- 给角色添加游戏ID
alter table honor_of_kings_hero add column game_id int comment '游戏ID';
-- 将现在王者荣耀的角色设置game_id=1
update honor_of_kings_hero set game_id=1;
insert into honor_of_kings_hero(name,gender,age,faction,release_date,game_id) values
('发条魔灵','女',28,'皮尔特沃夫','2011-06-01',2),
('德玛西亚之力','男',30,'德玛西亚','2010-04-27',2);
目前上述两张表,只是在逻辑上存在这样一层关系;在数据库层面,并未建立外键关联,所以是无法保证数据的一致性和完整性的,也就是如果我们删除了游戏表中的一条数据角色表中game_id 对应对应字段还存在但是已经没有关联关系了
1). 添加外键
语法CREATE TABLE 表名( 字段名 数据类型, ... [CONSTRAINT] [外键名称] FOREIGN KEY (外键字段名) REFERENCES 主表 (主表列名) );
ALTER TABLE 表名 ADD CONSTRAINT 外键名称 FOREIGN KEY (外键字段名) REFERENCES 主表 (主表列名) ;
为db_game 和 honor_of_kings_hero 添加外键
alter table honor_of_kings_hero add constraint fk_hkh_game foreign key (game_id) references tb_game(id);
执行删除db_game一条数据
添加了外键约束之后,我们再到dept表(父表)删除id为1的记录,然后看一下会发生什么现象。 此时将会报错,不能删除或更新父表记录,因为存在外键约束。
Cannot delete or update a parent row: a foreign key constraint fails(db_04.honor_of_kings_hero, CONSTRAINT fk_hkh_game FOREIGN KEY (game_id) REFERENCES tb_game (id))
2). 删除外键ALTER TABLE 表名 DROP FOREIGN KEY 外键名称;
-- 删除外键
alter table honor_of_kings_hero drop foreign key fk_hkh_game;
删除/更新行为
添加了外键之后,再删除父表数据时产生的约束行为,我们就称为删除/更新行为。具体的删除/更新行为有以下几种:
| 行为 | 说明 |
|---|---|
| NO ACTION | 当在父表中删除/更新对应记录时,首先检查该记录是否有对应外键,如果有则不允许删除/更新。 (与 RESTRICT 一致) 默认行为 |
| RESTRICT | 当在父表中删除/更新对应记录时,首先检查该记录是否有对应外键,如果有则不允许删除/更新。 (与 NO ACTION 一致) 默认行为 |
| CASCADE | 当在父表中删除/更新对应记录时,首先检查该记录是否有对应外键,如果有,则也删除/更新外键在子表中的记录。 |
| SET NULL | 当在父表中删除对应记录时,首先检查该记录是否有对应外键,如果有则设置子表中该外键值为null(这就要求该外键允许取null)。 |
| SET DEFAULT | 父表有变更时,子表将外键列设置成一个默认的值 (Innodb不支持) |
具体语法为:
ALTER TABLE 表名 ADD CONSTRAINT 外键名称 FOREIGN KEY (外键字段) REFERENCES 主表名 (主表字段名) ON UPDATE CASCADE ON DELETE CASCADE;
1). CASCADE
alter table honor_of_kings_hero add constraint fk_hkh_game foreign key (game_id) references tb_game(id) on update cascade on delete cascade;
原始数据
修改主表(主表id改为3后子表game_id也改变了)
B. 删除父表id为3的记录 子表也会删除
2). SET NULL
在进行测试之前,我们先需要删除上面建立的外键 fk_hkh_game。然后再通过数据脚本,将 honor_of_kings_hero、db_game表的数据恢复了。
alter table honor_of_kings_hero add constraint fk_emp_dept_id foreign key (game_id) references
tb_game(id) on update set null on delete set null ;
delete from tb_game where id=2;
接下来,我们删除id为2的数据,看看会发生什么样的现象。
honor_of_kings_hero 的game_id 值都为null了