浅析MySQL数据库中的外键约束

一、什么是主键、外键?

1、关系型数据库中的一条记录中有若干个属性,若其中某一个属性组(注意是组)能唯一标识一条记录,该属性组就可以成为一个主键 。

2、①外键(FK)是用于建立或加强两个表数据之间的链接的一列或多列。

      ②通过将表中主键值的一列或多列添加到另一个表中,可创建两个表之间的连接,这个列就成为第二个表的外键。

      ③外键约束的目的是控制存储在外表中的数据,同时可以控制对主键表中数据的修改。

      ④ 例如:publishers表中记录出版商的信息,titles表中记录书的信息,如果在publishers的表中删除一个出版商,而这个出版商的ID在titles表中记录书的信息时被使用了,则这两个表之间关联的完整性将被破坏,即titles表中该出版商的书籍因为与publisher表中的数据没有链接而变的孤立。

       ⑤外键约束可以防止这种情况的发生,如果主键表中数据的更改使得与外键表中数据的链接失效,则这种更改是不能实现的;如果试图删除主键表中的行或试图修改主键值,而该主键值与另一个表的外键约束值相关,则该操作不可实现。若要成功的更改或删除外键约束的行,可以现在外键表中删除外键数据或更改外键数据,然后将外键连接到不同的主键数据上去。

二、为什么要使用外键

下面我将通过一个问题(将用户admin的账户信息和其多个邮寄商品的信息保存到数据库中)的三种解决方案来说明为什么要使用外键。

方案一:使用一张表来存储用户的所有信息(包括账户信息和邮寄信息)

##创建用户信息表,里面存储用户admin的所有数据。
create table user_info(
  id char(36) primary key, //设置主键,此字段不能为null且不能重复。
  user_name varchar(30) not null,
  password varchar(30) not null,
  real_name varchar(8),
  mobile char(11),
  address varchar(150)
);
##向表中添加添加信息。id字段为主键,用来标识每条记录的唯一性。下面添加的是同一个用户admin三条不同的邮递信息。
insert into user_info (id,user_name,password,real_name,mobile,address) 
values ('51b28fe1-4ebf-41ac-a17b-d5e276861fd0','admin','123456','张三','18920120206','河南安阳');
insert into user_info (id,user_name,password,real_name,mobile,address) 
values ('cc95772b-75a2-4702-bd99-4c3b0322d606','admin','123456','李四','18617297545','北京海淀');
insert into user_info (id,user_name,password,real_name,mobile,address)
values ('c63028fd-cf8d-4dac-a278-b5cc8fd61e3c','admin','123456','王五','17694976949','山西大同');

分析:这种表结构存在严重的字段冗余(user_name和password列),如果个人信息字段比较多这一问题表现得会更加严重。

那怎么解决上述问题呢?让我们来看方案二。

方案二、使用一张表来存储用户的账户信息,另一张表存储用户的邮递信息。

##创建user_info表来存储用户的账户信息。
create table user_info(
  id char(36) primary key, ##设置主键,此字段不能为null且不能重复。
  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','admin','123456');

##创建address表来存储用户的邮递信息。
create table address(
  id char(36) primary key, ##设置主键,此字段不能为null且不能重复。
  user_info_id char(36),
  real_name varchar(8) not null,
  mobile char(11) not null,
  address varchar(150) not null
)
##下面添加的三条数据,字段user_info_id的值与user_info表中的id值相同,用来表示添加的邮递信息对应user_info表中的那条账户信息。
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中id为51b28fe1-4ebf-41ac-a17b-d5e276861fd0的数据删除,但此时地址表中数据将不再完整——找不到这些地址属于哪个用户;再例如也可以向address表中添加一条user_info_id不存在的地址信息(如:insert into address (id,user_info_id,real_name,mobile,address) values ('7da42cc6-36a6-4ad5-9998-71dbc30c8e17','ddc376dd-f8b3-42a6-b42a-db22abed1941','xiaowang','18338970095','北京东城区');)同样,该条数据并不完整,依然找不到这些地址属于哪个用户。那么这时候就需要使用到外键。

方案三、在address表中添加外键约束

##创建user_info表来存储用户的账户信息。
create table user_info(
  id char(36) primary key, ##设置主键,此字段不能为null且不能重复。
  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','admin','123456');
##创建address表来存储用户的邮递信息。
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) ##为address表添加外键,指向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','山西大同');

分析:这种方案为address表中添加了外键,指向user_info表的主键,该约束起到了保护数据完整性的作用:如果删除的用户信息id已经在address表中使用,则该条数据无法删除;无法向address表中添加用户id不存在的地址信息。

那我们来验证一下方案二中出现的问题:

①向address表中添加user_info不存在的id

##此user_info_id在user_info表中不存在。
insert into address (id,user_info_id,real_name,mobile,address) 
values ('bfb9472a-7911-4e6f-a479-3b71946eb8','51b28fe1-888f-41ac-a17b-d5e276861f','张三','18920120206','河南安阳');

②删除address表中正在使用的user_info表中id(即与address表外键相对应的user_info表中的主键值)

##删除address表中正在使用的user_info表中的数据
delete from  user_info where id='51b28fe1-4ebf-41ac-a17b-d5e276861fd0'

 我们从上面两点可以看出:在我们添加了外键约束之后,方案二中存在的问题迎刃而解。

 

 

 

  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值