【强制】不得使用外键与级联,一切外键概念必须在应用层解决.-《阿里Java规范》html
假设有一个score表 id是自增id,score是分数,student_id是学号。sql
另外一个student表,id是自增id,name是名字,student_id是学号。数据库
那么设计这个的时候就但愿有一个关联关系,让score的student_id指向student表的student_id,存在一个学生对应多个成绩的关系。因此我可使用如下SQL语句服务器
ALTER TABLE score ADD CONSTRAINT FOREIGN KEY (student_id) REFERENCES student(student_id);
建立一个外键索引完成这个规则并发
完成后的表关系以下框架
被指向的字段,具备惟一性高并发
能够保证成绩字段的一致性,即每一次插入一个score数据,首先要检测是否student表存在这个id,保证一致性性能
若是在外键类型上使用CASCADE
,则会保证在作更新和删除sutudent表的student_id时,触发一次级联操做,会同步更新score表的student_id或者删除student_id.设计
外键类型RESTRICT
也一样会作一次检测,但不会作级联操做,而是直接拒绝操做。
3d
知道外键是什么后,咱们来思考一个场景:
如今有一个电商系统,用户有一个帐户id,商品有一个商品id,这两个字段和订单绑定,此时订单id和帐户表ID构成一个外键关系,同时和商品表id也构成一个外键关系,那么我每次生成一笔订单,就须要向另外两张表查询检测一次数据,那么就存在几个问题:
这些问题在互联网公司会显得格外严重,由于访问流量大的时候以上问题基本上是彻底没法获得MySQL系统自己解决的
同时在作分库分表设计的时候,外键约束就会显得格外离谱。
同时MySQL系统的外键设计是背离部分SQL标准的
引用自博客园Eden: (https://www.cnblogs.com/discuss/articles/1862244.html)
对SQL标准的背离:若是ON UPDATE CASCADE或ON UPDATE SET NULL递归更新相同的表,以前在级联过程当中该表一被更新过,它就象RESTRICT同样动做。这意味着你不能使用自引用ON UPDATE CASCADE或者ON UPDATE SET NULL操做。这将阻止级联更新致使的无限循环。另外一方面,一个自引用的ON DELETE SET NULL是有可能的,就像一个自引用ON DELETE CASCADE同样。级联操做不能够被嵌套超过15层深。
对SQL标准的背离: 相似通常的MySQL,在一个插入,删除或更新许多行的SQL语句内,InnoDB逐行检查UNIQUE和FOREIGN KEY约束。按照SQL的标准,默认的行为应被延迟检查,即约束仅在整个SQL语句被处理以后才被检查。直到InnoDB实现延迟的约束检查以前,一些事情是不可能的,好比删除一个经过外键参考到自身的记录。
由于以上问题,咱们一般在建模时隐性设计外键约束,实际实现采用业务逻辑模拟外键的方式处理,这样能够解决把一致性所有放在DBA上的性能问题,同时咱们能够采用容许脏数据存在,而后定时数据清理的方案去保证数据处理的分时性能,避免高峰处理。
这样的好处:
我以为在部分业务场景下是能够考虑使用的,回到最开始的例子,教务系统的成绩模块重要的点再也不是性能问题,而是高可靠,由于对学校来讲,系统存在如下特色:
因此 不得使用外键与级联,一切外键概念必须在应用层解决。 大部分状况下正确,但一样我认为须要分业务场景解决,并不能一竿子打死。