【MySQL】表的約束(主鍵、唯一鍵、外鍵等約束類型詳解)、表的設計

目錄

1.數據庫約束

1.1 約束類型

1.2 null約束 — not null

1.3 unique — 唯一約束

1.4 default — 設置默認值

1.5 primary key — 主鍵約束

自增主鍵

自增主鍵的局限性:經典面試問題(進階問題)

1.6 foreign key — 外鍵約束

1.7 check約束(了解)

2. 表的設計

一對一

一對多

多對多


1.數據庫約束

  • 約束是數據庫針對里面的數據有一定的要求,有些數據認為是合法數據,有些數據是非法數據。這里給出的一組"檢驗規則”。
  • 數據庫自動的對數據的合法性進行校驗檢查的一系列機制。目的是為了保證數據庫中能夠避免被插入/修改一些非法的數據。

1.1 約束類型

  • not null — 指示某列不能存儲 NULL 值。 —— 必填項
  • unique —?保證某列的每行必須有(是)唯一的值,不能重復。 —— 學號,手機號,身份證號
  • default —?規定沒有給列賦值時的默認值。—— 默認值
  • primary key —?not null 和 unique 的結合。確保某列(或兩個列多個列的結合)有唯一標識(既不能為空,也不能重復),有助于更容易更快速地找到表中的一個特定的記錄。 —— 主鍵
  • foreign key —?保證一個表中的數據匹配另一個表中的值的參照完整性。 —— 外鍵
  • check —?保證列中的值符合指定的條件。對于MySQL數據庫,對CHECK子句進行分析,但是忽略 check子句。在mysql 5版本中,不支持,寫了不會報錯,但是沒有實際效果。這里不做過多介紹。

設置約束條件大部分都是在創建表的時候。

1.2 null約束 — not null

創建表時,可以指定某列不為空。未指定:此時表可以隨意插入空值。

可以使用 alter table給現有的表加約束,但用起來麻煩(支持的功能多),很少會使用。不做過多介紹。在創建表的時候要設計好表的屬性。這里我們為了方便演示每次刪了重新創建。

創建時,指定id 列為not null(不能為空),如果嘗試插入或者修改為空,都會報錯。

1.3 unique — 唯一約束

唯一:插入/修改數據的時候,會先查詢,看看數據是否已經存在。如果不存在,就能夠插入/修改成功,如果存在,則插入/修改失敗。

unique沒約束之前,可以插入多條重復的記錄

unique約束之后,指定id列為唯一,不能插入重復記錄

  • 報錯:重復條目。數據庫怎么知道的1存在?
  • 其實是在插入或者修改之前先觸發一次,查詢操作(正常插入直接插入,添加約束插入需要先查詢一下),這里是多了個查找數據的成本。所以有unique 的約束插入/修改要比沒有unique的約束插入/修改要慢一些。數據庫的查詢操作并不是像線性遍歷的方式,一條一條的查,有更快的方式,但是還是有查詢這個行為。
  • 數據庫引入約束之后,執行效率會受到影響,可能會降低很多。
  • 意味著數據庫是比較慢的系統,也比較吃資源的系統。在部署數據庫的服務器,它很容易成為整個系統的“性能瓶頸"。
  • 可靠數據角度:mysql數據庫處理的數據多,需要更多的時間更可靠的去處理數據。俗話說慢工出細活。
  • 性能效率角度:在現在很多高并發、大數據的情況下,mysql數據庫的表現就差強人意了。根據實際情況,可以搭配redis數據庫使用提高數據存儲和訪問。

1.4 default — 設置默認值

可以通過default 約束,來修改默認值。默認的默認值是空。

在insert 指定列插入的時候,其他未被指定到的列按照默認值來填充。

沒有設置默認值,默認值為null

設置默認值;插入時,name列不做指定,默認值無名氏

1.5 primary key — 主鍵約束

  • 主鍵,一行記錄在表中的"身份標識",手機號碼、身份證號碼、學號等
  • 要求唯一且不能為空,主鍵 = unique + not null ,
  • 一張表里只能有一個primary key。一個表里的記錄,只能有一個作為身份標識的數據。
  • 創建主鍵的時候,可以使用一個列作為主鍵,也可以使用多個列作為主鍵(復合/聯合主鍵,很少用)

  • 看起來和not null + unique是類似的,同樣對于帶有主鍵約束的表,每次插入數據/修改數據之前要都要先查詢操作,空的和重復的不會插入/修改。
  • mysql會把帶有unique 和 primary key的列自動生成索引,從而加快查詢速度。(后續會講解)

自增主鍵

如何保證主鍵唯一,mysql提供了一種"自增主鍵"這樣機制。

  • 主鍵經常會使用int / bigint類型。對于整數類型的主鍵,常配搭自增長 auto_increment 來使用。插入數據對應字段設置為null,mysql服務器會自動分配。從1開始,依次遞增的分配主鍵的值。
  • 自增主鍵 primary key auto_increment程序猿插入數據的時候,不必手動指定主鍵約束的值了,不用考慮重復的情況了。

給自增主鍵插入數據的時候,可以手動指定一個值,也可以讓mysql服務器自行分配。如果讓mysql服務器自行分配,在insert語句的時候,把id設為null 即可了。

mysql服務器自行分配:在insert語句的時候,把id設為null 即可了。

自增主鍵可以理解為:mysql服務器給每個表維護了一個全局變量,每次自行分配一個id,全局變量自增,下次分配接著上次的繼續分。

手動指定:

  • 分配的時候把4-99序號跳過了,浪費了一部分序號,但沒浪費空間。

  • 這里手動指定是可以插入4-99序號,但是mysql服務器不能自動分配4-99序號。
  • 如果mysql重復利用了中間的值,增長一定數據之后,就可能和100重復,因此mysql就需要時刻記得當前哪些id被分配了,哪些是空閑的,這么搞也能實現,太麻煩,效率也低。
  • 自增主鍵,相當于使用了一個變量,來保存了當前表的id的最大值,后續分配自增主鍵都是根據這個最大值來分配的。如果手動指定 id,也會更新最大值。

自增主鍵的局限性:經典面試問題(進階問題)

  1. 此處這里自增主鍵 自動分配 id,是有一定局限性的。
  2. 自增主鍵在單個mysql服務器,能很好的使用。
  3. 如果是一個分布式系統,有多個mysql服務器構成的集群,這時依靠自增主鍵就不行了。
  4. 面臨的數據量大(大數據),客戶端的請求量比較大(高并發),一臺服務器存儲管理不下,需要多臺機器(分布式)。例如某一個表或者某幾個表,數據量特別大。此時來了一個新的商品,進行分庫分表。此時新增商品,id如何分配呢?肯定是要把這個記錄保存在某個數據庫的表中,但是如何保證這里的id和另外兩個數據庫中id不重復呢?
  5. 分布式系統中生成唯一 id的算法,實現這個算法的具體方式有很多,我們通過下面公式思想實現。
  6. 分布式唯一id = 時間戳 + 機房編號/主機編號 + 隨機因子?
  7. +是指字符串拼接,不是算術相加。拼出來的結果是一個比較長的字符串

公式解讀:

  • 時間戳:如果添加商品的速度比較慢,直接使用時間戳表示就夠了,
  • 機房編號/主機號:但如果一個時間戳內,添加了多個商品,添加的多個商品,是要落到不同的主機上的。保證同一時間之內,添加到不同主機上的商品的編號,是不同的了。
  • 隨機因子:同一個ms之內,給同一個機器上添加的多個數據。隨機因子這里有一定概率生成相同的因子,但是概率比較小,可以忽略不計。

1.6 foreign key — 外鍵約束

描述兩張表之間相互關聯,這個關聯就是外鍵約束。外鍵用于關聯其他表的主鍵或唯一鍵。

  • 保證指定父表的列是帶索引的。創建主鍵約束(PRIMARY KEY)、唯一約束(UNIQUE)、外鍵約束(FOREIGN KEY)時,會自動創建對應列的索引。
  • 外鍵約束位置是在描述完,全部列之后寫的。前面其他約束則是緊跟對應列的后面。

先創建兩張表,class、student。

  • 如果不寫外鍵約束,此時student中的classId列與class中的classId列將沒有任何關聯。
  • references,JavaSE中引用(類型),此處表示了當前這個表的這一列中的數據,出自于另一個表的哪一列。
  • 此時student表中classId列的每行記錄,都在class表的classld列中存在。
  • class表中的數據,約束了 student表中的數據。
  • 把class表稱為“父表”(parent),約束其它表的表。
  • 把student表稱為“子表”(child),被其它表約束的表。
  • 指定外鍵約束的時候,要求父表中被關聯的這一列,是主鍵或者是unique約束的。否則子表不能關聯到該列,會報錯。

  • 班級表為空,插入學生記錄不會成功,報錯;要插入的外鍵在關聯表中沒有。
  • 這里不僅對插入有約束,還有修改也有約束

  • 插入記錄到班級表中

  • 插入記錄到學生表中,mysql會先拿著這個記錄的classld(外鍵約束)1,查看class表中classId有沒有,有則完成后續的插入,沒有插入失敗。

這里注意,studentId 為 2 ,是因為前面嘗試插入了一次,沒成功,但是自增主鍵增了。

  • 修改學生表中記錄,mysql會先拿著這個記錄的classld(外鍵約束)10,查看class表中classId有沒有,有則完成后續的插入,沒有插入失敗。要修改的外鍵在關聯表中沒有。

  • 針對子表進行插入/修改操作,會先查看當前插入/修改的被約束的值,是否在父表中存在,有則完成后續的插入/修改,沒有插入/修改失敗。但可以修改其它沒有約束的列。
  • 外鍵約束始終要保持,子表中的數據在對應的,父表的列中要存在。

父表在約束子表,子表也反向的約束了父表

  • 針對父表進行修改/刪除操作,如果當前被修改/刪除的值,已經被子表引用了,這樣的操作也會失敗。但可以修改該記錄其它列。或者也可以修改/刪除其它沒有被反向約束的記錄。外鍵準確來說,是兩個表的列產生關聯關系。其他的列是不受影響的。
  • 例如:嘗試刪除班級表里面的classld為1的記錄,發現刪除失敗。但可以修改該記錄的className。或者可以修改/刪除其它沒有被反向約束的記錄。

報錯原因:要刪除的記錄關聯到了其他表作為了外鍵,不能刪除。

  • 直接嘗試drop table class 來刪除表,也是不行的。要想刪除表,也需要先刪除記錄。

  • 正確的做法:先刪除子表,然后再刪除父表。

關于外鍵約束生活中的問題:

現在有一個電商網站,有個商品表(父表),訂單表(子表),其中關于goodsId列外鍵約束關聯。

有下面情景:一段時間后,商家想把這個襯衫給下架(刪除掉),要如何完成刪除。嘗試刪除父表數據的時候,如果父表的數據被子表引用,是不能刪除的,會報錯。電商網站如何做到,保證外鍵約束存在的前提下,實現"商品下架"功能的。

解決方法:

給商品表新增一個單獨的列,表示是否在線。(不在線就相當于下架了)

如果需要下架商品,使用update把 isOk 從1 修改為 0即可。此時實現下架并非是delete 而是 update 把是否下架字段進行修改。

查詢商品的時候,都加上where isOk = 1這樣的條件。如果為0,就間接實現了商品下架。

了解:

  • 我們在這里刪除都是邏輯刪除,把這個數據標記成無效,而不是直接把數據抹掉。
  • 電腦上刪除文件,也是通過邏輯刪除的方式實現的。這樣的刪除數據還在硬盤上,只不過是被標記成無效了。后續其他文件是可以重復利用這塊硬盤空間的。
  • 通過扔進回收站,清空回收站是不能把電腦的某個文件徹底刪除的。硬盤上數據徹底消亡,需要時間等待后續有文件把這塊標記無效的空間重復利用了才會真正消失。
  • 如何才是正確的徹底刪除數據的方式,通過物理刪除 -》把硬盤砸了。
  • 所以按照邏輯刪除的思路,表中的數據是否會無限的擴張,是否就會導致硬盤空間被占滿。當然會有的。通過添加硬盤(比較便宜)、增加主機(分布式)等的方式,來進一步的擴充存儲空間。

1.7 check約束(了解)

MySQL使用時不報錯,但忽略該約束:

2. 表的設計

根據實際的需求場景,明確當前要創建幾個表,每個表的結構以及屬性,這些表之間是否存在一定聯系。

設計表,分兩步走:

1、梳理清楚需求中的 "實體"

例如:

一般來說每個實體,都需要安排一個表,表的列就對應到實體的各個屬性。

2、梳理清楚實體之間的關系,按照關系,帶入到既定的公式中。

實體之間的關系,主要有三種(嚴格的說是四種) 一對一, 一對多 , 多對多 , 沒關系都屬于設計數據庫表結構的固定套路。

三大范式:

一對一

一個學生,只能有一個賬號。一個賬號,只能供一個學生所有。—— 1、創建一個大表,包含全部列。2、創建兩個表、相互關聯。

一對多

一個班級可以包含多個學生。一個學生只能處于一個班級。—— 通過外鍵關聯,要注意誰為父表,誰為子表。

  • mysql不支持數組類型使用mysql時是用第二種方式來實現的。
  • 第一種寫法,可以在redis這樣能夠支持數組類型的數據庫中使用。

多對多

一個學生可以選擇多個課程。一個課程也可以提供給多個學生。—— 借助關聯表

  • 沒關系:上述三種關系都無法套入進去。此時這樣的表就完全沒有關系,各自獨立設計即可,不必考慮對方。
  • 一般來說,只要實體和關系都明確了,此時表的設計就基本差不多了。如果實體比較多,關系比較復雜,可以畫一個"實體關系圖"(ER圖),來表示這個關系。
  • 實際開發中,很少會畫ER圖。即使畫也不必嚴格的遵守ER圖的語法,大概畫一下就行。


好啦Y(^o^)Y,本節內容到此就結束了。下一篇內容一定會火速更新!!!

后續還會持續更新MySQL方面的內容,還請大家多多關注本博主,第一時間獲取新鮮的知識。

如果覺得文章不錯,別忘了一鍵三連喲!?

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/pingmian/77663.shtml
繁體地址,請注明出處:http://hk.pswp.cn/pingmian/77663.shtml
英文地址,請注明出處:http://en.pswp.cn/pingmian/77663.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

數據結構-C語言版本(三)棧

數據結構中的棧:概念、操作與實戰 第一部分 棧分類及常見形式 棧是一種遵循后進先出(LIFO, Last In First Out)原則的線性數據結構。棧主要有以下幾種實現形式: 1. 數組實現的棧(順序棧) #define MAX_SIZE 100typedef struct …

如何以特殊工藝攻克超薄電路板制造難題?

一、超薄PCB的行業定義與核心挑戰 超薄PCB通常指厚度低于1.0毫米的電路板,而高端產品可進一步壓縮至0.4毫米甚至0.2毫米以下。這類電路板因體積小、重量輕、熱傳導性能優異,被廣泛應用于折疊屏手機、智能穿戴設備、醫療植入器械及新能源汽車等領域。然而…

AI 賦能 3D 創作!Tripo3D 全功能深度解析與實操教程

大家好,歡迎來到本期科技工具分享! 今天要給大家帶來一款革命性的 AI 3D 模型生成平臺 ——Tripo3D。 無論你是游戲開發者、設計師,還是 3D 建模愛好者,只要想降低創作門檻、提升效率,這款工具都值得深入了解。 接下…

如何理解抽象且不易理解的華為云 API?

API的概念在華為云的使用中非常抽象,且不容易理解,用通俗的語言 形象的比喻來講清楚——什么是華為云 API,怎么用,背后原理,以及主要元素有哪些,盡量讓新手也能明白。 🧠 一句話先理解&#xf…

第 7 篇:總結與展望 - 時間序列學習的下一步

第 7 篇:總結與展望 - 時間序列學習的下一步 (圖片來源: Guillaume Hankenne on Pexels) 恭喜你!如果你一路跟隨這個系列走到了這里,那么你已經成功地完成了時間序列分析的入門之旅。我們從零開始,一起探索了時間數據的基本概念、…

PPT無法編輯怎么辦?原因及解決方法全解析

在日常辦公中,我們經常會遇到需要編輯PPT的情況。然而,有時我們會發現PPT文件無法編輯,這可能由多種原因引起。今天我們來看看PPT無法編輯的幾種常見原因,并提供實用的解決方法,幫助你輕松應對。 原因1:文…

前端面試題---GET跟POST的區別(Ajax)

GET 和 POST 是兩種 HTTP 請求方式,它們在傳輸數據的方式和所需空間上有一些重要區別: ? 一句話概括: GET 數據放在 URL 中,受限較多;POST 數據放在請求體中,空間更大更安全。 📦 1. 所需空間…

第 5 篇:初試牛刀 - 簡單的預測方法

第 5 篇:初試牛刀 - 簡單的預測方法 經過前面四篇的學習,我們已經具備了處理時間序列數據的基本功:加載、可視化、分解以及處理平穩性。現在,激動人心的時刻到來了——我們要開始嘗試預測 (Forecasting) 未來! 預測是…

從代碼學習深度學習 - 學習率調度器 PyTorch 版

文章目錄 前言一、理論背景二、代碼解析2.1. 基本問題和環境設置2.2. 訓練函數2.3. 無學習率調度器實驗2.4. SquareRootScheduler 實驗2.5. FactorScheduler 實驗2.6. MultiFactorScheduler 實驗2.7. CosineScheduler 實驗2.8. 帶預熱的 CosineScheduler 實驗三、結果對比與分析…

k8s 基礎入門篇之開啟 firewalld

前面在部署k8s時,都是直接關閉的防火墻。由于生產環境需要開啟防火墻,只能放行一些特定的端口, 簡單記錄一下過程。 1. firewall 與 iptables 的關系 1.1 防火墻(Firewall) 定義: 防火墻是網絡安全系統&…

RSS 2025|蘇黎世提出「LLM-MPC混合架構」增強自動駕駛,推理速度提升10.5倍!

論文題目:Enhancing Autonomous Driving Systems with On-Board Deployed Large Language Models 論文作者:Nicolas Baumann,Cheng Hu,Paviththiren Sivasothilingam,Haotong Qin,Lei Xie,Miche…

list的學習

list的介紹 list文檔的介紹 list是可以在常數范圍內在任意位置進行插入和刪除的序列式容器,并且該容器可以前后雙向迭代。list的底層是雙向鏈表結構,雙向鏈表中每個元素存儲在互不相關的獨立節點中,在節點中通過指針指向其前一個元素和后一…

生物信息學技能樹(Bioinformatics)與學習路徑

李升偉 整理 生物信息學是一門跨學科領域,涉及生物學、計算機科學以及統計學等多個方面。以下是關于生物信息學的學習路徑及相關技能的詳細介紹。 一、基礎理論知識 1. 生物學基礎知識 需要掌握分子生物學、遺傳學、細胞生物學等相關概念。 對基因組結構、蛋白質…

AOSP Android14 Launcher3——遠程窗口動畫關鍵類SurfaceControl詳解

在 Launcher3 執行涉及其他應用窗口(即“遠程窗口”)的動畫時,例如“點擊桌面圖標啟動應用”或“從應用上滑回到桌面”的過渡動畫,SurfaceControl 扮演著至關重要的角色。它是實現這些跨進程、高性能、精確定制動畫的核心技術。 …

超詳細實現單鏈表的基礎增刪改查——基于C語言實現

文章目錄 1、鏈表的概念與分類1.1 鏈表的概念1.2 鏈表的分類 2、單鏈表的結構和定義2.1 單鏈表的結構2.2 單鏈表的定義 3、單鏈表的實現3.1 創建新節點3.2 頭插和尾插的實現3.3 頭刪和尾刪的實現3.4 鏈表的查找3.5 指定位置之前和之后插入數據3.6 刪除指定位置的數據和刪除指定…

17.整體代碼講解

從入門AI到手寫Transformer-17.整體代碼講解 17.整體代碼講解代碼 整理自視頻 老袁不說話 。 17.整體代碼講解 代碼 import collectionsimport math import torch from torch import nn import os import time import numpy as np from matplotlib import pyplot as plt fro…

前端性能優化:所有權轉移

前端性能優化:所有權轉移 在學習rust過程中,學到了所有權概念,于是便聯想到了前端,前端是否有相關內容,于是進行了一些實驗,并整理了這些內容。 所有權轉移(Transfer of Ownership)…

Missashe考研日記-day23

Missashe考研日記-day23 0 寫在前面 博主前幾天有事回家去了,斷更幾天了不好意思,就當回家休息一下調整一下狀態了,今天接著開始更新。雖然每天的博客寫的內容不算多,但其實還是挺費時間的,比如這篇就花了我40多分鐘…

Docker 中將文件映射到 Linux 宿主機

在 Docker 中,有多種方式可以將文件映射到 Linux 宿主機,以下是常見的幾種方法: 使用-v參數? 基本語法:docker run -v [宿主機文件路徑]:[容器內文件路徑] 容器名稱? 示例:docker run -it -v /home/user/myfile.txt:…

HarmonyOS-ArkUI-動畫分類簡介

本文的目的是,了解一下HarmonyOS動畫體系中的分類。有個大致的了解即可。 動效與動畫簡介 動畫,是客戶端提升界面交互用戶體驗的一個重要的方式。可以使應用程序更加生動靈越,提高用戶體驗。 HarmonyOS對于界面的交互方面,圍繞回歸本源的設計理念,打造自然,流暢品質一提…