MySQL數據庫的主鍵和外鍵詳解
主鍵
主鍵的定義
主鍵:表中經常有一個列或多列的組合,其值能唯一地標識表中的每一行。這樣的一列或多列稱為表的主鍵,通過它可強制表的實體完整性。當創建或更改表時可通過定義 PRIMARY KEY 約束來創建主鍵。一個表只能有一個 PRIMARY KEY 約束,而且 PRIMARY KEY 約束中的列不能接受空值。由於 PRIMARY KEY 約束確保唯一數據,所以經常用來定義標識列。
作用:
1)保證實體的完整性;
2)加快數據庫的操作速度
3)在表中添加新記錄時,DBMS會自動檢查新記錄的主鍵值,不允許該值與其他記錄的主鍵值重復。
4)DBMS自動按主鍵值的順序顯示表中的記錄。如果沒有定義主鍵,則按輸入記錄的順序顯示表中的記錄。
聯合主鍵
關系數據庫實際上還允許通過多個字段唯一標識記錄,即兩個或更多的字段都設置為主鍵,這種主鍵被稱為聯合主鍵。
對於聯合主鍵,允許一列有重復,只要不是所有主鍵列都重復即可。
主鍵的特性
主鍵的必要性
在有些數據庫中,雖然主鍵不是必需的,但最好為每個表都設置一個主鍵,不管是單主鍵還是復合主鍵。它存在代表着表結構的完整性,表的記錄必須得有唯一區分的字段,主鍵主要是用於其他表的外鍵關聯,以及本記錄的修改與刪除。
主鍵的無意義性
由於主鍵的作用十分重要,如何選取主鍵會對業務開發產生重要影響。如果我們以學生的身份證號作為主鍵,似乎能唯一定位記錄。然而,身份證號也是一種業務場景,如果身份證號升位了,或者需要變更,作為主鍵,不得不修改的時候,就會對業務產生嚴重影響。
選取主鍵的一個基本原則是:不使用任何業務相關的字段作為主鍵。
因此,身份證號、手機號、郵箱地址這些看上去可以唯一的字段,均不可用作主鍵。
主鍵的選擇
- 自增整數類型:數據庫會在插入數據時自動為每一條記錄分配一個自增整數,這樣我們就完全不用擔心主鍵重復,也不用自己預先生成主鍵;
- 全局唯一GUID類型:使用一種全局唯一的字符串作為主鍵,類似
8f55d96b-8acc-4636-8cb8-76bf8abc2f57。GUID算法通過網卡MAC地址、時間戳和隨機數保證任意計算機在任意時間生成的字符串都是不同的,大部分編程語言都內置了GUID算法,可以自己預算出主鍵。
對於大部分應用來說,通常自增類型的主鍵就能滿足需求
定義的自增性整數類型的主鍵一般使用是
BIGINT NOT NULL AUTO_INCREMENT類型。如果使用INT自增類型,那么當一張表的記錄數超過2147483647(約21億)時,會達到上限而出錯。使用BIGINT自增類型則可以最多約922億億條記錄。
外鍵
外鍵的定義
如果公共關鍵字在一個關系中是主關鍵字,那么這個公共關鍵字被稱為另一個關系的外鍵。由此可見,外鍵表示了兩個關系之間的相關聯系。以另一個關系的外鍵作主關鍵字的表被稱為主表,具有此外鍵的表被稱為主表的從表。外鍵又稱作外關鍵字。
舉例:
student表:

class表:

由於一個班級可以有多個學生,在關系模型中,這兩個表的關系可以稱為“一對多”,即一個class的記錄可以對應多個student表的記錄。
為了表達這種一對多的關系,我們需要在student表中加入一列class_id,讓它的值與class表的某條記錄相對應。
這樣,我們就可以根據class_id這個列直接定位出一個student表的記錄應該對應到class的哪條記錄。
在student表中,通過class_id的字段,可以把數據與另一張表關聯起來,這種列稱為外鍵。
外鍵並不是通過列名實現的,而是通過定義外鍵約束實現的:
//定義外鍵約束
ALTER TABLE student
ADD CONSTRAINT fk_class_id //外鍵約束的名稱fk_class_id可以任意
FOREIGN KEY (class_id) //指定了class_id作為外鍵
REFERENCES class (id); //指定了這個外鍵將關聯到class表的id列(即class表的主鍵)
class_id為學生表的外鍵。(此時
student表中的class_id與class表中的id表示的含義相同)此時外鍵表是
student表,主鍵表是class表。
要刪除一個外鍵約束,也是通過ALTER TABLE實現的:
ALTER TABLE student
DROP FOREIGN KEY fk_class_id;
由於外鍵約束會降低數據庫的性能,大部分互聯網應用程序為了追求速度,並不設置外鍵約束,而是僅靠應用程序自身來保證邏輯的正確性。這種情況下,
class_id僅僅是一個普通的列,只是它起到了外鍵的作用而已。
選取設置 MySQL 外鍵的字段
定義一個外鍵時,需要遵守下列規則:
- 父表必須已經存在於數據庫中,或者是當前正在創建的表。如果是后一種情況,則父表與子表是同一個表,這樣的表稱為自參照表,這種結構稱為自參照完整性。
- 必須為父表定義主鍵。
- 主鍵不能包含空值,但允許在外鍵中出現空值。也就是說,只要外鍵的每個非空值出現在指定的主鍵中,這個外鍵的內容就是正確的。
- 在父表的表名后面指定列名或列名的組合。這個列或列的組合必須是父表的主鍵或候選鍵。
- 外鍵中列的數目必須和父表的主鍵中列的數目相同。
- 外鍵中列的數據類型必須和父表主鍵中對應列的數據類型相同。
外鍵的作用
保持數據一致性,完整性。主要目的是控制存儲在外鍵表中的數據。 使兩張表形成關聯,外鍵只能引用外表中的列的值或使用空值
外鍵約束
MySQL外鍵約束(FOREIGN KEY)用來在兩個表的數據之間建立鏈接,它可以是一列或者多列。一個表可以有一個或多個外鍵。
外鍵是表的一個字段,不是本表的主鍵,但對應另一個表的主鍵。定義外鍵后,不允許刪除另一個表中具有關聯關系的行。
主表(父表)
對於兩個具有關聯關系的表而言,相關聯字段中主鍵所在的表就是主表。
被引用的表叫主表(父表)。
從表(子表)
對於兩個具有關聯關系的表而言,相關聯字段中外鍵所在的表就是從表。
定義了外鍵的表叫從表(子表)。
外鍵約束的作用:
阻止執行
- 從表插入新行,其外鍵值不是主表的主鍵值便阻止插入;
- 從表修改外鍵值,新值不是主表的主鍵值便阻止修改;
- 主表刪除行,其主鍵值在從表里存在便阻止刪除(要想刪除,必須先刪除從表的相關行);
- 主表修改主鍵值,舊值在從表里存在便阻止修改(要想修改,必須先刪除從表的相關行)。
級聯執行
- 主表刪除行,連帶從表的相關行一起刪除;
- 主表修改主鍵值,連帶從表相關行的外鍵值一起修改。兩種方法提供給用戶選擇。無論選取哪種方法,從表里都不會有多余行。從另一個角度理解,用拒絕同一事物在從表中的標志與主表不一致來實現與主表中的標志一致。
兩種實現方法,通過下面方式選擇:
- 界面:設級聯更新、級聯刪除兩個選擇方框,選取則級聯執行、不選取則阻止執行;
- 命令:設E)kSCM)E、RESTRICT兩個可選項,CASCADE為級聯執行、RESTRICT為阻止執行。
CASCADE:級聯刪除
在外鍵表的最后,加上on delete cascade 就是級聯刪除
再刪除主表數據時和主表關聯的子表數據也會刪除
CREATE TABLE `student` (
`id` bigint(64) NOT NULL AUTO_INCREMENT,
`class_id` bigint(64) DEFAULT NULL,
`name` varchar(32) COLLATE utf8_bin DEFAULT NULL,
`age` int(32) DEFAULT NULL,
`sex` varchar(32) COLLATE utf8_bin DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `fk_class_id` (`class_id`),
CONSTRAINT `fk_class_id` FOREIGN KEY (`class_id`) REFERENCES `class` (`id`)
on delete cascade,
)
所謂的級聯刪除,就是刪除主鍵表的同時,外鍵表同時刪除。
以上面的例子將就是,假如班級表中的某個班級被刪除了,那么在學生表中要想查詢這個被刪除的班級號所對應的班級信息就會報錯,因為已經不存在這個班級了,所以,刪除班級表(主鍵表)時必須刪除其他與之關聯的表,這里就說明了外鍵的作用,保持數據的一致性、完整性。當然反過來講,你刪除學生表中的記錄,並不影響班級表中的數據,你查詢班級號也能正確查詢。所以刪除外鍵表中的數據並不影響主鍵表。
RESTRICT:約束/限制、NO ACTION(非活動,默認)
當取值為No Action或者Restrict時,則當在主鍵表中刪除對應記錄時,首先檢查該記錄是否有對應外鍵,如果有則不允許刪除。(即外鍵表約束主鍵表)
SET NULL:級聯置空
在在外鍵表的最后,加上on delete set null就是級聯置空
再刪除主表數據時,會把和主表關聯的外鍵設置成NULL
CREATE TABLE `student` (
`id` bigint(64) NOT NULL AUTO_INCREMENT,
`class_id` bigint(64) DEFAULT NULL,
`name` varchar(32) COLLATE utf8_bin DEFAULT NULL,
`age` int(32) DEFAULT NULL,
`sex` varchar(32) COLLATE utf8_bin DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `fk_class_id` (`class_id`),
CONSTRAINT `fk_class_id` FOREIGN KEY (`class_id`) REFERENCES `class` (`id`)
on delete set null,
)
當取值為Set Null時,則當在主鍵表中刪除對應記錄時,首先檢查該記錄是否有對應外鍵,如果有則設置子表中該外鍵值為null,(一樣是外鍵表約束主鍵表,不過這就要求該外鍵允許取null)。
NO ACTION和RESTRICT的區別:只有在及個別的情況下會導致區別,前者是在其他約束的動作之后執行,后者具有最高的優先權執行。
注意
刪除表時,應該先刪子表,后刪父表,除非使用casecade constraints 解除關聯。
先刪除父表時會報錯:有一個被foreign keys關聯的 key的字段在子表中
<e>查詢:drop table class
錯誤代碼: 3730
Cannot drop table 'class' referenced by a foreign key constraint 'fk_class_id' on table 'student'.
如果一定要先刪除父表
使用casecade constraints解除關聯就可以刪掉父表
drop table parent cascade constranints;

如有需要的朋友可以關注我的公眾號並回復:數據庫電子書 ,即可獲取以下免費PDF資料

