在MySQL 3.23.44版本后,InnoDB引擎类型的表支持了外键约束,外键的使用条件:
1.两个表必须是 InnoDB表,MyISAM类型表不支持外键;
2.外键列必须建立了索引,MySQL 4.1.2以后的版本在建立外键时会自动创建索引,但如果在较早的版本则需要显示建立;
3.外键关系的两个表的列必须是数据类型相似,也就是可以相互转换类型的列,比如int和tinyint可以,而int和char则不可以;
外键的好处是可以使得两张表建立一定关联关系,保证两个表中数据的一致性和实现一些级联操作;
外键的定义语法:
[CONSTRAINT symbol] FOREIGN KEY [id] (index_col_name, ...)
REFERENCES tbl_name (index_col_name, ...)
[ON DELETE {RESTRICT | CASCADE | SET NULL | NO ACTION | SET DEFAULT}]
[ON UPDATE {RESTRICT | CASCADE | SET NULL | NO ACTION | SET DEFAULT}]
该语法可以在 CREATE TABLE 和 ALTER TABLE 时使用,如果不指定CONSTRAINT symbol,MYSQL会自动生成一个名字。
ON DELETE、ON UPDATE表示事件触发限制,可设参数:
RESTRICT(限制外表中的外键改动)
CASCADE(跟随外键改动)
SET NULL(设空值)
SET DEFAULT(设默认值)
NO ACTION(无动作,默认的)
举个例子演示一下,创建lingdao和yuangong两个表,领导表是主键,员工表是外键:
建表:
CREATE TABLE lingdao (id int(11) NOT NULL auto_increment,
name varchar(64) default '',
PRIMARY KEY (id)
) ENGINE=InnoDB DEFAULT CHARSET='utf8';
CREATE TABLE yuangong (
id int(11) NOT NULL auto_increment,
lingdao_id int(11) default NULL,
name varchar(64) default '',
PRIMARY KEY (id),
KEY dage_id (lingdao_id),
CONSTRAINT yg_ibfk_1 FOREIGN KEY (lingdao_id) REFERENCES lingdao (id)
) ENGINE=InnoDB DEFAULT CHARSET='utf8';
插入个领导:
mysql> INSERT INTO lingdao(name) VALUES('张总');
Query OK, 1 row affected (0.01 sec)
mysql> SELECT * FROM lingdao;
+----+--------+
| id | name |
+----+--------+
| 1 | 张总 |
+----+--------+
1 row in set (0.00 sec)
插入个员工:
mysql>INSERT INTO yuangong(lingdao_id,name) VALUES(1,'跑腿小兵A');
Query OK, 1 row affected (0.02 sec)
mysql> SELECT * FROM yuangong;
+----+---------+--------------+
| id | lingdao_id | name |
+----+---------+--------------+
| 1 | 1 | 跑腿小兵A|
+----+---------+--------------+
好,现在两个表中都有了数据,而且也建立了外键关系,下面来进行下面的两种操作:
把领导删除:
mysql> DELETE FROM lingdao WHERE id=1; ERROR 1451 (23000): Cannot delete or update a parent row: a foreign key constraint fails (`jbsage`.`yuangong`, CONSTRAINT `yg_ibfk_1` FOREIGN KEY (`lingdao_id`) REFERENCES `lingdao` (`id`))提示:无法删除?因为外键约束存在,张总下面还有员工。如果要删除张总,必须先把yuangong表中的跑腿小兵A删除掉,才可以删除张总。可以分下面两步操作:
删除员工表中的数据,mysql> DELETE FROM yuangong WHERE id = 1; Query OK, 1 row affected (0.00 sec)
再删除领导表中的数据
mysql> DELETE FROM lngidao WHERE id = 1;
Query OK, 1 row affected (0.00 sec)
注意:上面两个id都等于1,分别是两个表中不同的id。这只是为了演示,不要混淆了。如果是真正的开发过程可不都是这样。
2.插入一个新的女下属:
mysql> INSERT INTO yuangong(lingdao_id,name) VALUES(2,'端茶小秘A');
ERROR 1452 (23000): Cannot add or update a child row: a foreign key constraint fails (`jbsage`.`yuangong`, CONSTRAINT `yg_ibfk_1` FOREIGN KEY (`lingdao_id`) REFERENCES `lingdao` (`id`))
小秘来了,但是没有领导啊,分给谁?不存在lingdao_id等于2的领导,这是一个无效的不存在的领导,所以不允许插入数据。
上面的两种情况,就是外键存在时的常见操作,这种约束的目的就保持了不同表中数据的一致性。
下面针对第一种情况,我们介绍一下外键的强大之处:
增加外键约束事件触发限制,首先移除之前的外键约束
mysql> ALTER TABLE yuangong drop foreign key yg_ibfk_1;
Query OK, 1 row affected (0.03 sec)
Records: 1 Duplicates: 0 Warnings: 0
重新再yuangong表上加上外键约束,这次增加事件触发限制 on delete cascade on update cascade;
mysql> ALTER TABLE yuangong add foreign key(lingdao_id) references lingdao(id) on delete cascade on update cascade;
Query OK, 1 row affected (0.03 sec)
Records: 1 Duplicates: 0 Warnings: 0
再次尝试删掉张总:
mysql> DELETE FROM lingdao WHERE id=1;
Query OK, 1 row affected (0.01 sec)
mysql> SELECT * FROM lingdao;
Empty set (0.01 sec)
mysql> SELECT * FROM yuangong;
Empty set (0.00 sec)
可以看到,只是对lingdao表执行了一条DELETE操作,但是这回对应的员工表中张总的下属信息也被删除了,这就是on delete cascade!删除操作会自己的级联把主键和外键表中关联的数据一起删掉。
这里是已DELETE删除操作为例,UPDATE更新表的操作原理和过程也是类似的。