干说无意,我们用例子分析;
create table user_info(
id char(36) primary key,
user_name varchar(30) not null,
password varchar(30) not null,
real_name varchar(8),
mobile char(11),
address varchar(150)
);
insert into user_info (id,user_name,password,real_name,mobile,address)
values ('51b28fe1-4ebf-41ac-a17b-d5e276861fd0','fuliuqingfeng','123456','张三','18920120206','河南安阳');
insert into user_info (id,user_name,password,real_name,mobile,address)
values ('cc95772b-75a2-4702-bd99-4c3b0322d606','fuliuqingfeng','123456','李四','18617297545','北京海淀');
insert into user_info (id,user_name,password,real_name,mobile,address)
values ('c63028fd-cf8d-4dac-a278-b5cc8fd61e3c','fuliuqingfeng','123456','王五','17694976949','山西大同');
我们先用 Navicat(我是用的这个)执行上段代码;就是创建一个表,并往其中输入数据,然后查询表可得下表:
很容易看出,中间 user_name 和 password 因为其内容相同而造成数据冗余,浪费空间,试想一下,如果每个人都要浪费同样的空间,中国所有人都存入数据库中会浪费多少空间?因此,我们需要优化存储方法;
create table user_info(
id char(36) primary key,
user_name varchar(30) not null,
password varchar(30) not null
)
insert into user_info (id,user_name,password) values ('51b28fe1-4ebf-41ac-a17b-d5e276861fd0','fuliuqingfeng','123456');
create table address(
id char(36) primary key,
user_info_id char(36),
real_name varchar(8) not null,
mobile char(11) not null,
address varchar(150) not null
)
insert into address (id,user_info_id,real_name,mobile,address)
values ('bfb9472a-7911-4e6f-a479-3b719454ebab','51b28fe1-4ebf-41ac-a17b-d5e276861fd0','张三','18920120206','河南安阳');
insert into address (id,user_info_id,real_name,mobile,address)
values ('5227c6b9-45a2-44aa-8ac0-1f63a38d3b65','51b28fe1-4ebf-41ac-a17b-d5e276861fd0','李四','18617297545','北京海淀');
insert into address (id,user_info_id,real_name,mobile,address)
values ('30b8584b-aa6a-4516-a623-03f487058586','51b28fe1-4ebf-41ac-a17b-d5e276861fd0','王五','17694976949','山西大同');
为了节省存储空间,我们将冗余的数据取出,生成一个表 user_info,并用一个主键标记(想不出来官方用语,这里知道是啥意思就完事了),然后再将其他没有产生冗余的属性建立另一个表 address,并将表 user_info 的主键 id 作为表 address 的一个列属性使用,这样的话就会产生下面两个表的效果:
这样就会产生两个表,减少了一部分冗余(当冗余越严重,此做法收益越大);但是我们又发现一个问题,信息完整才有意义,上图是一个人的完整信息,若我们将 user_name 中的信息删除,信息就会缺失,变得毫无意义;若我们在 address 增加 一个 user_info_id 不为“51b28fe1-4ebf-41ac-a17b-d5e276861fd0”(唯一性),并且其他属性任意填写的一行垃圾信息,我们会发现垃圾信息会成功添加进去,那么原有的个人信息完整性会遭到破坏,因此,我们需要限制对创建好的信息的修改与增删,使操作不能破坏个人信息的完整性;
create table user_info(
id char(36) primary key,
user_name varchar(30) not null,
password varchar(30) not null
)
insert into user_info (id,user_name,password) values ('51b28fe1-4ebf-41ac-a17b-d5e276861fd0','fuliuqingfeng','123456');
create table address(
id char(36) primary key,
user_info_id char(36),
real_name varchar(8) not null,
mobile char(11) not null,
address varchar(150) not null,
constraint address_user_info_id_fk foreign key(user_info_id) references user_info(id) ###产生外键关系
)
insert into address (id,user_info_id,real_name,mobile,address)
values ('bfb9472a-7911-4e6f-a479-3b719454ebab','51b28fe1-4ebf-41ac-a17b-d5e276861fd0','张三','18920120206','河南安阳');
insert into address (id,user_info_id,real_name,mobile,address)
values ('5227c6b9-45a2-44aa-8ac0-1f63a38d3b65','51b28fe1-4ebf-41ac-a17b-d5e276861fd0','李四','18617297545','北京海淀');
insert into address (id,user_info_id,real_name,mobile,address)
values ('30b8584b-aa6a-4516-a623-03f487058586','51b28fe1-4ebf-41ac-a17b-d5e276861fd0','王五','17694976949','山西大同');
乍一看,仿佛没啥区别,细心的话可以发现这次比上次多了一行 constraint address_user_info_id_fk foreign key(user_info_id) references user_info(id) 代码,这一行代码是使两个表产生外键联系,不能再随意增添删除信息了,此时在执行 delete from user_info where id = '51b28fe1-4ebf-41ac-a17b-d5e276861fd0' 删除操作,系统就会提醒你这是关键信息,不让删除;同理执行 insert into address (id,user_info_id,real_name,mobile,address)
values ('3000584b-aa6a-4516-a623-03f487058586','51b28fe1-4ebf-41ac-a17b-d5e276860000','王五','17694976949','山西大同');(分别修改了id 和 user_info_id),系统会提醒你该信息的 user_info_id 在 user_info 表中没有与其对应的信息,不让你添加;这就保护了个人的信息安全。
小结:外键的作用就是使两个需要有联系的表产生约束,使其不能随意执行增添删除操作从而破坏信息完整性。