MySQL外來鍵約束_ON DELETE CASCADE/ON UPDATE CASCADE
MySQL通過外來鍵約束實現資料庫的參照完整性,外來鍵約束條件可在建立外來鍵時指定,table的儲存引擎只能是InnoDB,因為只有這種儲存模式才支援外來鍵。
外來鍵約束條件有以下4種:
(1)restrict方式:同no action,都是立即檢查外來鍵約束;
- - 限制,指的是如果子表引用父表的某個欄位的值,那麼不允許直接刪除父表的該值。
(2)cascade方式:在父表上update/delete記錄時,同步update/delete子表的匹配記錄 ;
On delete cascade從mysql3.23.50開始可用,on update cascade從mysql4.0.8開始可用 ; -- 級聯,刪除/更新父表的某條記錄,子表中引用該值的記錄會自動被刪除/更新。
(3)No action方式:如果子表中有匹配的記錄,則不允許對父表對應候選鍵進行update/delete操作 這個是ANSI SQL-92標準,從mysql4.0.8開始支援;
--無參照完整性關係,有了也不生效。
(4)set null方式:在父表上update/delete記錄時,將子表上匹配記錄的列設為null 要注意子表的外來鍵列不能為not null
On delete set null從mysql3.23.50開始可用;,on update set null從mysql4.0.8開始可用 。
首先建立一個使用者表,並插入兩條記錄:
複製程式碼
mysql> create table t_group -> (id int auto_increment primary key, -> name varchar(20)) -> engine=InnoDB; Query OK, 0 rows affected (0.08 sec) mysql> insert into t_group values (1,'Group_1'),(2,'Group_2'); Query OK, 2 rows affected (0.04 sec) Records: 2 Duplicates: 0 Warnings: 0 mysql> select * from t_group; +----+---------+ | id | name | +----+---------+ | 1 | Group_1 | | 2 | Group_2 | +----+---------+ 2 rows in set (0.00 sec)
1.級聯方式
建立級聯子表:
mysql> create table t_user
-> (id int not null primary key,
-> name varchar(10),groupid int,
-> foreign key(groupid) references t_group(id)
-> on delete cascade on update cascade)
-> engine=InnoDB;
Query OK, 0 rows affected (0.08 sec)
完整性約束測試,以下例子都省略完整性測試:
mysql> insert into t_user values (1,'dayu',1),(2,'duoduo',2);
Query OK, 2 rows affected (0.08 sec)
Records: 2 Duplicates: 0 Warnings: 0
mysql> insert into t_user values (1,'huanhuan',1); //實體完整性測試,不能插入重複主鍵值
ERROR 1062 (23000): Duplicate entry '1' for key 'PRIMARY'
mysql> insert into t_user values (3,'maiqi',3); //參照完整性測試,不能插入在主表中不存在的外來鍵值
ERROR 1452 (23000): Cannot add or update a child row: a foreign key constraint fails (`test`.`t_user`, CONSTRAINT `t_user_ibfk_1` FOREIGN KEY (`groupid`) REFERENCES `t_group` (`id`) ON DELETE CASCADE ON UPDATE CASCADE)
級聯測試:
mysql> select * from t_user;
+----+--------+---------+
| id | name | groupid |
+----+--------+---------+
| 1 | dayu | 1 |
| 2 | duoduo | 2 |
+----+--------+---------+
2 rows in set (0.00 sec)
mysql> update t_group set id=3 where id=2; //從主表中更新一個記錄
Query OK, 1 row affected (0.02 sec)
Rows matched: 1 Changed: 1 Warnings: 0
mysql> select * from t_user; /改變主表資料,從表資料隨著更新
±—±-------±--------+
| id | name | groupid |
±—±-------±--------+
| 1 | dayu | 1 |
| 2 | duoduo | 3 |
±—±-------±--------+
2 rows in set (0.00 sec)
mysql> select * from t_user;
±—±-------±--------+
| id | name | groupid |
±—±-------±--------+
| 1 | dayu | 1 |
| 2 | duoduo | 3 |
±—±-------±--------+
2 rows in set (0.00 sec)
mysql> delete from t_group where id=3; //從主表中刪除一個記錄
Query OK, 1 row affected (0.03 sec)
mysql> select * from t_user; //子表中對應的記錄自動被刪除
+----+------+---------+
| id | name | groupid |
+----+------+---------+
| 1 | dayu | 1 |
+----+------+---------+
1 row in set (0.00 sec)
2.置空模式(set null,主表記錄被刪除,從表中對應的值設定為NULL)
首先建立一個子表:
mysql> select * from t_group;
+----+---------+
| id | name |
+----+---------+
| 1 | Group_1 |
| 2 | Group_2 |
+----+---------+
2 rows in set (0.00 sec)
mysql> create table t_user_1
-> (id int not null primary key,
-> name char(10),groupid int,
-> foreign key(groupid) references t_group(id)
-> on delete set null on update set null)
-> engine=InnoDB;
Query OK, 0 rows affected (0.11 sec)
mysql> insert into t_user_1 values (1,'dayu',1),(2,'duoduo',2),(3,'huanhuan',2),(4,'maiqi',1);
Query OK, 4 rows affected (0.02 sec)
Records: 4 Duplicates: 0 Warnings: 0
mysql> select * from t_user_1;
+----+----------+---------+
| id | name | groupid |
+----+----------+---------+
| 1 | dayu | 1 |
| 2 | duoduo | 2 |
| 3 | huanhuan | 2 |
| 4 | maiqi | 1 |
+----+----------+---------+
4 rows in set (0.00 sec)
mysql> update t_group set id=3 where id=1;
Query OK, 1 row affected (0.03 sec)
Rows matched: 1 Changed: 1 Warnings: 0
mysql> select * from t_user_1;
+----+----------+---------+
| id | name | groupid |
+----+----------+---------+
| 1 | dayu | NULL |
| 2 | duoduo | 2 |
| 3 | huanhuan | 2 |
| 4 | maiqi | NULL |
+----+----------+---------+
4 rows in set (0.00 sec)
mysql> delete from t_group where id=2; //從主表中刪除一個記錄
Query OK, 1 row affected (0.01 sec)
mysql> select * from t_user_1; //子表中對應的屬性值被自動設定為NULL
+----+----------+---------+
| id | name | groupid |
+----+----------+---------+
| 1 | dayu | NULL |
| 2 | duoduo | NULL |
| 3 | huanhuan | NULL |
| 4 | maiqi | NULL |
+----+----------+---------+
4 rows in set (0.00 sec)
3.禁止模式(no action/restrict),如果在子表中有引用,則不允許在主表中進行更新或刪除
首先建立一個子表:
mysql> select * from t_group;
+----+---------+
| id | name |
+----+---------+
| 1 | Group_1 |
| 2 | Group_2 |
+----+---------+
2 rows in set (0.00 sec)
mysql> create table t_user_2
-> (id int not null primary key,
-> name char(10),groupid int,
-> foreign key(groupid) references t_group(id)
-> on delete no action on update restrict)
-> engine=InnoDB;
Query OK, 0 rows affected (0.11 sec)
mysql> insert into t_user_2 values (1,'dayu',1),(2,'duoduo',2),(3,'huanhuan',2),(4,'maiqi',1);
Query OK, 4 rows affected (0.02 sec)
Records: 4 Duplicates: 0 Warnings: 0
mysql> select * from t_user_2;
+----+----------+---------+
| id | name | groupid |
+----+----------+---------+
| 1 | dayu | 1 |
| 2 | duoduo | 2 |
| 3 | huanhuan | 2 |
| 4 | maiqi | 1 |
+----+----------+---------+
4 rows in set (0.00 sec)
mysql> update t_group set id=3 where id=1;
ERROR 1451 (23000): Cannot delete or update a parent row: a foreign key constraint fails (`test`.`t_user_2`, CONSTRAINT `t_user_2_ibfk_1` FOREIGN KEY (`groupid`) REFERENCES `t_group` (`id`) ON DELETE NO ACTION)
mysql> delete from t_group where id=2;
ERROR 1451 (23000): Cannot delete or update a parent row: a foreign key constraint fails (`test`.`t_user_2`, CONSTRAINT `t_user_2_ibfk_1` FOREIGN KEY (`groupid`) REFERENCES `t_group` (`id`) ON DELETE NO ACTION)
4.主從表的刪除
刪除從表沒有限制,如下:
mysql> drop table t_user_2;
Query OK, 0 rows affected (0.01 sec)
如果存在引用的從表,則主要不能隨意刪除:
mysql> drop table t_group;
ERROR 1217 (23000): Cannot delete or update a parent row: a foreign key constraint fails
經過以上測試,瞭解到MySQL通過外來鍵約束實現了資料的完整性與一致性。