詳解MariaDB數據庫的外鍵約束

1.什麼是外鍵約束

外鍵約束(foreign key)就是表與表之間的某種約定的關係,因爲這種關係的存在,咱們可以讓表與表之間的數據,更加的完整,關連性更強。數據庫

關於數據表的完整性和關連性,能夠舉個例子測試

有二張表,一張是用戶表,一張是訂單表:code

1.若是我刪除了用戶表裏的用戶,那麼訂單表裏面跟這個用戶有關的數據,就成了無頭數據了,不完整了。
2.若是我在訂單表裏面,隨便插入了一條數據,這個訂單在用戶表裏面,沒有與之對應的用戶。這樣數據也不完整了。

若是有外鍵的話,就方便多了,能夠不讓用戶刪除數據,或者刪除用戶的話,經過外鍵一樣刪除訂單表裏面的數據,這樣也能讓數據完整。索引

經過外鍵約束,每次插入或更新數據表時,都會檢查數據的完整性。ci

2.建立外鍵約束

2.1 方法一:經過create table建立外鍵

語法:unicode

create table 數據表名稱(
...,
[CONSTRAINT [約束名稱]] FOREIGN KEY [外鍵字段] 
    REFERENCES [外鍵表名](外鍵字段,外鍵字段2…..)
    [ON DELETE CASCADE ]
    [ON UPDATE CASCADE  ]
)

參數的解釋:rem

RESTRICT: 拒絕對父表的刪除或更新操做。
CASCADE: 從父表刪除或更新且自動刪除或更新子表中匹配的行。ON DELETE CASCADE和ON UPDATE CASCADE均可用

注意:on update cascade是級聯更新的意思,on delete cascade是級聯刪除的意思,意思就是說當你更新或刪除主鍵表,那外鍵表也會跟隨一塊兒更新或刪除。io

精簡化後的語法:innodb

foreign key 當前表的字段 references 外部表名 (關聯的字段) type=innodb

2.1.1 插入測試數據

例子:咱們建立一個數據庫,包含用戶信息表和訂單表table

MariaDB [book]> create database market;             # 建立market數據庫
Query OK, 1 row affected (0.00 sec)

MariaDB [book]> use market;                         # 使用market數據庫
Database changed

MariaDB [market]> create table userprofile(id int(11) not null auto_increment, name varchar(50) not null default '', sex int(1) not null default '0', primary key(id))ENGINE=innodb;    # 建立userprofile數據表,指定使用innodb引擎
Query OK, 0 rows affected (0.07 sec)

MariaDB [market]> create table user_order(o_id int(11) auto_increment, u_id int(11) default '0', username varchar(50), money int(11), primary key(o_id), index(u_id), foreign key order_f_key(u_id) references userprofile(id) on delete cascade on update cascade);            # 建立user_order數據表,同時爲user_order表的u_id字段作外鍵約束,綁定userprofile表的id字段
Query OK, 0 rows affected (0.04 sec)

MariaDB [market]> insert into userprofile(name,sex)values('HA',1),('LB',2),('HPC',1);       # 向userprofile數據表插入三條記錄
Query OK, 3 rows affected (0.01 sec)
Records: 3  Duplicates: 0  Warnings: 0

MariaDB [market]> select * from userprofile;        # 查詢userprofile數據表的全部記錄
+----+------+-----+
| id | name | sex |
+----+------+-----+
|  1 | HA   |   1 |
|  2 | LB   |   2 |
|  3 | HPC  |   1 |
+----+------+-----+
3 rows in set (0.00 sec)

MariaDB [market]> insert into user_order(u_id,username,money)values(1,'HA',234),(2,'LB',146),(3,'HPC',256);                     # 向user_order數據表插入三條記錄
Query OK, 3 rows affected (0.02 sec)
Records: 3  Duplicates: 0  Warnings: 0

MariaDB [market]> select * from user_order;         # 查詢user_order數據表的全部記錄
+------+------+----------+-------+
| o_id | u_id | username | money |
+------+------+----------+-------+
|    1 |    1 | HA       |   234 |
|    2 |    2 | LB       |   146 |
|    3 |    3 | HPC      |   256 |
+------+------+----------+-------+
3 rows in set (0.00 sec)

MariaDB [market]> select id,name,sex,money,o_id from userprofile,user_order where id=u_id;      # 聯表查詢
+----+------+-----+-------+------+
| id | name | sex | money | o_id |
+----+------+-----+-------+------+
|  1 | HA   |   1 |   234 |    1 |
|  2 | LB   |   2 |   146 |    2 |
|  3 | HPC  |   1 |   256 |    3 |
+----+------+-----+-------+------+
3 rows in set (0.03 sec)

2.1.2 測試級聯刪除

MariaDB [market]> delete from userprofile where id=1;       # 刪除user表中id爲1的數據
Query OK, 1 row affected (0.01 sec)

MariaDB [market]> select id,name,sex,money,o_id from userprofile,user_order where id=u_id;
+----+------+-----+-------+------+
| id | name | sex | money | o_id |
+----+------+-----+-------+------+
|  2 | LB   |   2 |   146 |    2 |
|  3 | HPC  |   1 |   256 |    3 |
+----+------+-----+-------+------+
2 rows in set (0.00 sec)

MariaDB [market]> select * from user_order;                 # 查看order表的數據
+------+------+----------+-------+
| o_id | u_id | username | money |
+------+------+----------+-------+
|    2 |    2 | LB       |   146 |
|    3 |    3 | HPC      |   256 |
+------+------+----------+-------+
3 rows in set (0.00 sec)

2.1.3 測試級聯更新

更新數據以前的狀態

MariaDB [market]> select * from userprofile;                # 查看userprofile表的數據
+----+------+-----+
| id | name | sex |
+----+------+-----+
|  2 | LB   |   2 |
|  3 | HPC  |   1 |
+----+------+-----+
3 rows in set (0.00 sec)

MariaDB [market]> select * from user_order;                 # 查看order表的數據
+------+------+----------+-------+
| o_id | u_id | username | money |
+------+------+----------+-------+
|    2 |    2 | LB       |   146 |
|    3 |    3 | HPC      |   256 |
+------+------+----------+-------+
3 rows in set (0.00 sec)

更新數據

MariaDB [market]> update userprofile set id=6 where id=2;   # 把userprofile數據表中id爲2的用戶改成id爲6
Query OK, 1 row affected (0.02 sec)
Rows matched: 1  Changed: 1  Warnings: 0

更新數據後的狀態

MariaDB [market]> select id,name,sex,money,o_id from userprofile,user_order where id=u_id;      # 聯表查詢,能夠看出表中已經沒有id爲2的用戶了
+----+------+-----+-------+------+
| id | name | sex | money | o_id |
+----+------+-----+-------+------+
|  6 | LB   |   2 |   146 |    2 |
|  3 | HPC  |   1 |   256 |    3 |
+----+------+-----+-------+------+
2 rows in set (0.00 sec)

MariaDB [market]> select * from userprofile;                # 查看userprofile表的數據,id只剩下3和6
+----+------+-----+
| id | name | sex |
+----+------+-----+
|  3 | HPC  |   1 |
|  6 | LB   |   2 |
+----+------+-----+
2 rows in set (0.00 sec)

MariaDB [market]> select * from user_order;                 # 查看user_order表的數據,u_id也改成6
+------+------+----------+-------+
| o_id | u_id | username | money |
+------+------+----------+-------+
|    2 |    6 | LB       |   146 |
|    3 |    3 | HPC      |   256 |
+------+------+----------+-------+
2 rows in set (0.00 sec)

2.1.4 測試數據完整性

MariaDB [market]> insert into user_order(u_id,username,money)values(5,"XJ",345);        # 單獨向user_order數據表中插入數據,插入數據失敗
ERROR 1452 (23000): Cannot add or update a child row: a foreign key constraint fails (`market`.`user_order`, CONSTRAINT `user_order_ibfk_1` FOREIGN KEY (`u_id`) REFERENCES `userprofile` (`id`) ON DELETE CASCADE ON UPDATE CASCADE)

在上面的例子中,user_order表的外鍵約束,user_order表受userprofile表的約束

user_order裏面插入一條數據u_id爲5用戶,在userprofile表裏面根本沒有,因此插入數據失敗

先向userprofile表中插入記錄,再向user_order表中插入記錄就能夠了

MariaDB [market]> insert into userprofile values(5,"XJ",1);         # 先向userprofile數據表中插入id爲5的記錄,插入數據成功
Query OK, 1 row affected (0.01 sec)

MariaDB [market]> insert into user_order(u_id,username,money) values(5,"XJ",345);       # 再向user_order數據表中插入數據,成功
Query OK, 1 row affected (0.00 sec)

MariaDB [market]> select * from userprofile;                # 查詢userprofile數據表中的全部記錄
+----+------+-----+
| id | name | sex |
+----+------+-----+
|  3 | HPC  |   1 |
|  5 | XJ   |   1 |
|  6 | LB   |   2 |
+----+------+-----+
3 rows in set (0.00 sec)

MariaDB [market]> select * from user_order;                 # 查詢user_order數據表中的全部記錄
+------+------+----------+-------+
| o_id | u_id | username | money |
+------+------+----------+-------+
|    2 |    6 | LB       |   146 |
|    3 |    3 | HPC      |   256 |
|    5 |    5 | XJ       |   345 |
+------+------+----------+-------+
3 rows in set (0.01 sec)

2.2 方法二:經過alter table建立外鍵和級聯更新,級聯刪除

語法:

alter table 數據表名稱 add 
    [constraint [約束名稱] ]  foreign key (外鍵字段,..) references 數據表(參照字段,...) 
    [on update cascade|set null|no action]
    [on delete cascade|set null|no action]
)

例子:

MariaDB [market]> create table user_order1(o_id int(11) auto_increment,u_id int(11) default "0",username varchar(50),money int(11),primary key(o_id),index(u_id));          # 建立user_order1數據表,建立表時不使用外鍵約束
Query OK, 0 rows affected (0.11 sec)

MariaDB [market]> show create table user_order1;            # 查看user_order1數據表的建立信息,沒有外鍵約束
+-------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Table       | Create Table                                                                                                                                                                                                                                                                                                   |
+-------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| user_order1 | CREATE TABLE `user_order1` (
  `o_id` int(11) NOT NULL AUTO_INCREMENT,
  `u_id` int(11) DEFAULT '0',
  `username` varchar(50) COLLATE utf8_unicode_ci DEFAULT NULL,
  `money` int(11) DEFAULT NULL,
  PRIMARY KEY (`o_id`),
  KEY `u_id` (`u_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci |
+-------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.01 sec)

MariaDB [market]> alter table user_order1 add foreign key(u_id) references userprofile(id) on delete cascade on update cascade;             # 使用alter修改user_order1數據表,爲user_order1數據表添加外鍵約束
Query OK, 0 rows affected (0.05 sec)               
Records: 0  Duplicates: 0  Warnings: 0

MariaDB [market]> show create table user_order1;            # 查看user_order1數據表的建立信息,已經添加了外鍵約束
+-------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Table       | Create Table                                                                                                                                                                                                                                                                                                                                                                                                                               |
+-------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| user_order1 | CREATE TABLE `user_order1` (
  `o_id` int(11) NOT NULL AUTO_INCREMENT,
  `u_id` int(11) DEFAULT '0',
  `username` varchar(50) COLLATE utf8_unicode_ci DEFAULT NULL,
  `money` int(11) DEFAULT NULL,
  PRIMARY KEY (`o_id`),
  KEY `u_id` (`u_id`),
  CONSTRAINT `user_order1_ibfk_1` FOREIGN KEY (`u_id`) REFERENCES `userprofile` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci |
+-------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)

3.刪除外鍵

語法

alter table 數據表名稱 drop foreign key 約束(外鍵)名稱

例子:

MariaDB [market]> show create table user_order1;            # 查看user_order1數據表的建立信息,包含外鍵約束
+-------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Table       | Create Table                                                                                                                                                                                                                                                                                                                                                                                                                               |
+-------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| user_order1 | CREATE TABLE `user_order1` (
  `o_id` int(11) NOT NULL AUTO_INCREMENT,
  `u_id` int(11) DEFAULT '0',
  `username` varchar(50) COLLATE utf8_unicode_ci DEFAULT NULL,
  `money` int(11) DEFAULT NULL,
  PRIMARY KEY (`o_id`),
  KEY `u_id` (`u_id`),
  CONSTRAINT `user_order1_ibfk_1` FOREIGN KEY (`u_id`) REFERENCES `userprofile` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci |
+-------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)

MariaDB [market]> alter table user_order1 drop foreign key user_order1_ibfk_1;          # 爲user_order1數據表刪除外鍵約束,外鍵名稱必須與從`show create table user_order1`語句中查到的相同
Query OK, 0 rows affected (0.05 sec)               
Records: 0  Duplicates: 0  Warnings: 0

MariaDB [market]> show create table user_order1;            # 查看user_order1數據表的建立信息,外鍵約束已經被刪除了
+-------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Table       | Create Table                                                                                                                                                                                                                                                                                                   |
+-------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| user_order1 | CREATE TABLE `user_order1` (
  `o_id` int(11) NOT NULL AUTO_INCREMENT,
  `u_id` int(11) DEFAULT '0',
  `username` varchar(50) COLLATE utf8_unicode_ci DEFAULT NULL,
  `money` int(11) DEFAULT NULL,
  PRIMARY KEY (`o_id`),
  KEY `u_id` (`u_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci |
+-------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)

4.使用外鍵約束的條件

要想外鍵建立成功,必須知足如下4個條件:

一、確保參照的表和字段存在。 
二、組成外鍵的字段被索引。 
三、必須使用type指定存儲引擎爲:innodb.
四、外鍵字段和關聯字段,數據類型必須一致。

5.使用外鍵約束須要的注意事項

1.on delete cascade  on update cascade 添加級聯刪除和更新:
2.確保參照的表userprofile中id字段存在。
3.確保組成外鍵的字段u_id被索引
4.必須使用type指定存儲引擎爲:innodb。
5.外鍵字段和關聯字段,數據類型必須一致。
相關文章
相關標籤/搜索