⭐⭐⭐ Spring Boot 项目实战 ⭐⭐⭐ Spring Cloud 项目实战
《Dubbo 实现原理与源码解析 —— 精品合集》 《Netty 实现原理与源码解析 —— 精品合集》
《Spring 实现原理与源码解析 —— 精品合集》 《MyBatis 实现原理与源码解析 —— 精品合集》
《Spring MVC 实现原理与源码解析 —— 精品合集》 《数据库实体设计合集》
《Spring Boot 实现原理与源码解析 —— 精品合集》 《Java 面试题 + Java 学习指南》

摘要: 原创出处 飞天小牛肉 「小牛肉」欢迎转载,保留摘要,谢谢!


🙂🙂🙂关注微信公众号:【芋道源码】有福利:

  1. RocketMQ / MyCAT / Sharding-JDBC 所有源码分析文章列表
  2. RocketMQ / MyCAT / Sharding-JDBC 中文注释源码 GitHub 地址
  3. 您对于源码的疑问每条留言都将得到认真回复。甚至不知道如何读源码也可以请教噢。
  4. 新的源码解析文章实时收到通知。每周更新一篇左右。
  5. 认真的源码交流微信群。

大家在学习数据库的过程中一定都接触过外键这个概念,并且在各种课后习题中外键还是一个非常重要的考察内容,但是在实际的企业开发过程中,你会发现外键是被严格禁止使用的,当需要多个表之间进行关联时,做法是冗余相关字段,而不是建立外键。

为什么?

什么是外键?

两张表有关联关系,才会涉及外键的概念。举个例子,有两张表:

1)学生表(学生 id、学生姓名);

CREATE TABLE `student` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '学生id',
`name` varchar(256) NOT NULL COMMENT '学生姓名',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='学生表';

2)成绩表(成绩 id、学生 id,分数),对于成绩表来说,学生 id 就是外键。

CREATE TABLE `score` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '成绩 id',
`student_id` bigint(20) unsigned NOT NULL COMMENT '学生id',
`score` int(20) unsigned NOT NULL COMMENT '分数'
PRIMARY KEY (`id`),
KEY `student_id` (`student_id`),
CONSTRAINT `fk_student_id` FOREIGN KEY (`student_id`) REFERENCES `student` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='成绩表';

如上,我们通过 foreign key ... references ... 来定义外键,将当前表的字段关联到另一张表的某个字段。

外键和主键一样,都是一种约束,外键约束也称为引用约束或引用完整性约束):

  1. 外键列必须引用另一个表中的主键或唯一键列;
  2. 外键列必须满足引用完整性,也就是说,它们包含的值必须存在于被引用表的主键或唯一键列中。

通俗来说:

  1. 成绩表插入数据时,student_id 必须是学生表已存在的 id;
  2. 学生表删除/更新数据时,会自动删除/更新成绩表中引用 student.id 的数据(级联)。

为什么不推荐使用外键?

阿里的开发手册中提到:

【强制】不得使用外键与级联,一切外键概念必须在应用层解决。

定义外键之后,数据库的每次操作都需要去检查外键约束。对于插入来说,影响了插入速度;对于更新来说,级联更新是强阻塞,存在数据库更新风暴(Database Update Storm)的风险。

所谓 Database Update Storm,指的是在高并发环境下,多个客户端同时对数据库进行大量的更新操作,存在锁竞争问题甚至死锁,从而导致数据库性能急剧下降或完全崩溃。

另外,当数据量非常大的时候,常见手段是分库分表,但外键通常难以跨越不同数据库来建立联系,数据的一致性更难维护。

因此,外键与级联并不适合分布式、高并发集群,但单机低并发业务可以考虑使用外键保证一致性和完整性。

文章目录
  1. 1. 什么是外键?
  2. 2. 为什么不推荐使用外键?