【強制】不得使用外鍵與級聯,一切外鍵概念必須在應用層解決.-《阿里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上的性能問題,同時咱們能夠採用容許髒數據存在,而後定時數據清理的方案去保證數據處理的分時性能,避免高峯處理。
這樣的好處:
我以爲在部分業務場景下是能夠考慮使用的,回到最開始的例子,教務系統的成績模塊重要的點再也不是性能問題,而是高可靠,由於對學校來講,系統存在如下特色:
因此 不得使用外鍵與級聯,一切外鍵概念必須在應用層解決。 大部分狀況下正確,但一樣我認爲須要分業務場景解決,並不能一竿子打死。