为什么现在大家都不用外键了(二)?

2022-01-20 00:00:00 修改 数据 删除 约束 学员
前言

MySQL外键(FOREIGNKEY)是表的一个特殊字段,用来建立主表与从表的关联关系,为两个表的数据建立连接,约束两个表中数据的一致性和完整性。

之前的篇文章相关文章(「技术讨论」为什么大家很少使用外键了?),总结了一些不使用外键的场景以及使用外键的优势之处。

本篇文章会基于实例来说明外键约束虽会保证表间数据的关系“始终完整一致”,但在实际操作中,每次做DELETE 或者UPDATE都必须考虑外键约束,会导致开发的时候很痛苦。

保持数据的一致性和完整性,主要体现在下面两个方面:

阻止执行

  • 从表插入新行,其外键值不是主表的主键值便阻止插入;


  • 从表修改外键值,新值不是主表的主键值便阻止修改;


  • 主表删除行,其主键值在从表里存在便阻止删除(要想删除,必须先删除从表的相关行);


  • 主表修改主键值,旧值在从表里存在便阻止修改(要想修改,必须先删除从表的相关行)。


级联执行

  • 主表删除行,连带从表的相关行一起删除;


  • 主表修改主键值,连带从表相关行的外键值一起修改。

 
下面我们举个例子来说明一下:
 
1.创建两个table,“教练”和“学员”,table“学员”带有外键约束。
CREATE TABLE jiaolian(   `jiaolian_id` INT AUTO_INCREMENT,   `jiaolian_name` VARCHAR(30),   PRIMARY KEY (`jiaolian_id`));
CREATE TABLE xueyuan( `xueyuan_id` INT AUTO_INCREMENT, `jiaolian_id` INT, `xueyuan_name` VARCHAR(30), FOREIGN KEY (`jiaolian_id`) REFERENCES `jiaolian` (`jiaolian_id`),   PRIMARY KEY (`xueyuan_id`));
 
2. 增加两个“教练”,两个“学员”。
insert into jiaolian(jiaolian_name) values("司机老李");insert into jiaolian(jiaolian_name) values("司机老林");insert into xueyuan(jiaolian_id,xueyuan_name) values(1,"徒弟张三");insert into xueyuan(jiaolian_id,xueyuan_name) values(2,"徒弟李四");

3.再增加一个“学员”,不存在的jiaolian_id,执行失败了。
insert into xueyuan(jiaolian_id,xueyuan_name) values(3,"徒弟王五");  #error

4. 删除一个“教练”,“教练”有关联的“学员”,执行失败。
delete from jiaolian where jiaolian_name="司机老李";  #error

5. 先删除“教练关联的“学员,再删除“教练,执行成功。
delete from xueyuan where xueyuan_name="徒弟张三";delete from jiaolian where jiaolian_name="司机老李";
 
结论

通过这个例子,我们可以看到,外键约束会保证表间数据的关系“始终完整一致”。


虽然将数据的一致性和完整性判断托付给了数据库完成,减少了程序的代码量。但在实际操作中,每次做DELETE 或者UPDATE都必须考虑外键约束,会导致开发的时候很痛苦,测试数据极为不方便。


在使用外键的情况下,每次修改数据都需要去另外一个表检查数据,需要获取额外的锁。

在高并发大流量事务场景,使用外键可能容易造成死锁,以及数据库资源出现瓶颈,所以一般互联网行业高频率高并发不建议使用。


一般来说,在业务代码中实现的时候,只要在应用层按照设计之初的这种固有关联逻辑,来处理数据即可,并不需要在数据库层面进行外键约束。

END

相关文章