数据库的外键约束,可以让数据进行一致性更新,但是会有一定的性能损耗,线上业务使用不多。通常上述级联更新和删除都是由应用层业务逻辑进行判断并实现。
--
-- 表结构 摘自 MySQL 官方文档
--
mysql> create table parent (
-> id int not null,
-> primary key (id)
-> ) engine=innodb;
Query OK, 0 rows affected (0.14 sec)
mysql> create table child (
-> id int,
-> parent_id INT,
-> index par_ind (parent_id),
-> foreign key (parent_id)
-> references parent(id)
-> on delete cascade on update cascade -- 比官网例子增加 update cascade
-> ) engine=innodb;
Query ok, 0 rows affected (0.15 sec)
mysql> insert into child values(1,1); -- 我们插入一条数据,id=1,parent_id=1
ERROR 1452 (23000): Cannot add or update a child row: a foreign key constraint fails (`burn_test`.`child`, CONSTRAINT `child_ibfk_1` FOREIGN KEY (`parent_id`) REFERENCES `parent` (`id`) ON DELETE CASCADE)
-- 直接报错了,因为此时parent表中没有任何记录
mysql> insert into parent values(1); -- 现在parent中插入记录
Query OK, 1 row affected (0.03 sec)
mysql> insert into child values(1,1); -- 然后在child中插入记录,且parent_id是在parent中存在的
Query OK, 1 row affected (0.02 sec)
mysql> insert into child values(1,2); -- 插入parent_id=2的记录,报错。因为此时parent_id=2的记录不存在
ERROR 1452 (23000): Cannot add or update a child row: a foreign key constraint fails (`burn_test`.`child`, CONSTRAINT `child_ibfk_1` FOREIGN KEY (`parent_id`) REFERENCES `parent` (`id`) ON DELETE CASCADE)
mysql> select * from child;
+------+-----------+
| id | parent_id |
+------+-----------+
| 1 | 1 | -- parent_id = 1
+------+-----------+
1 row in set (0.00 sec)
mysql> select * from parent;
+----+
| id |
+----+
| 1 | -- 根据表结构的定义(Foreign_key),这个值就是 child表中的id
+----+
1 row in set (0.00 sec)
mysql> update parent set id=100 where id=1;
Query OK, 1 row affected (0.04 sec)
Rows matched: 1 Changed: 1 Warnings: 0
mysql> select * from parent;
+-----+
| id |
+-----+
| 100 | -- 已经设置成了100
+-----+
1 row in set (0.00 sec)
mysql> select * from child;
+------+-----------+
| id | parent_id |
+------+-----------+
| 1 | 100 | -- 自动变化,这是on update cascade的作用,联级更新,parent更新,child也跟着更新
+------+-----------+
1 row in set (0.00 sec)
mysql> delete from parent where id=100; -- 删除这条记录
Query OK, 1 row affected (0.03 sec)
mysql> select * from parent; -- id=100的记录已经被删除了
Empty set (0.00 sec)
mysql> select * from child; -- id=1,parent_id=100的记录跟着被删除了。on delete cascade的作用
Empty set (0.00 sec)
mysql> alter table child drop foreign key child_ibfk_1; -- 删除 之前的外键
Query OK, 0 rows affected (0.07 sec)
Records: 0 Duplicates: 0 Warnings: 0
mysql> alter table child add foreign key(parent_id)
-> references parent(id) on update cascade on delete restrict; -- 使用严格模式
Query OK, 0 rows affected (0.27 sec)
Records: 0 Duplicates: 0 Warnings: 0
mysql> insert into parent values(50);
Query OK, 1 row affected (0.03 sec)
mysql> insert into child values(3,50);
Query OK, 1 row affected (0.03 sec)
mysql> insert into child values(3,51); -- 和之前一样会提示错误
ERROR 1452 (23000): Cannot add or update a child row: a foreign key constraint fails (`burn_test`.`child`, CONSTRAINT `child_ibfk_1` FOREIGN KEY (`parent_id`) REFERENCES `parent` (`id`) ON UPDATE CASCADE)
mysql> delete from parent where id=50; -- 删除失败了,因为是restrict模式
ERROR 1451 (23000): Cannot delete or update a parent row: a foreign key constraint fails (`burn_test`.`child`, CONSTRAINT `child_ibfk_1` FOREIGN KEY (`parent_id`) REFERENCES `parent` (`id`) ON UPDATE CASCADE)
-- 注意,delete 后面说明都不写表示 no action == restrict
作者:殷建卫 链接:https://www.yuque.com/yinjianwei/vyrvkf 来源:殷建卫 - 架构笔记 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。