日期:2014-05-16  浏览次数:20639 次

玩转MySQL的外键约束之级联删除篇

如今,许多关系型数据库管理系统都提供了外键约束这一强大的功能特性,它能够帮助我们自动地触发指定的动作,诸如删掉、更新数据库表的记录等,从而维护各数据库表之间预定义的关系。本文将演示如何在MySQL中利用外键约束以级联方式删除数据。

?

  对于PHP开发人员来说,在MySQL中使用InnoDB表时可以利用外键约束提供的许多的便利之处,尽管MySQL宣布将来的版本支持MyISAM表。本文将演示当更新和删除父表数据时如何维护一个数据库的完整性。

?

一、简介

?

  在上一篇文章中,我们讲解了如何在MySQL的InnoDB表中结合使用外键约束,即当父表中的数据更新的同时如何触发对子表数据的级联更新操作。说老实话,从字面上描述级联更新过程有些令人费解,如果通过SQL代码来演示的话则要轻松得多。那么,我们先用文章做简单表述,然后给出具体的代码。在最简单的情况下,这个过程首先要创建一个父表和一个子表,在子表中定义一个外键,然后规定当父表的数据更新时将发生什么动作。

?

  使用外键约束的主要好处是,我们可以在数据库级别很轻松地对表之间的关系进行处理,而无需在与数据层交互的应用程序内部实现这些逻辑。值得一提的是,这对于性能来说,可能会有一些损失,尤其是程序规模较大的时候。当然,数据库性能问题不在本文的讨论范围之内,下面我们演示如何使用外键约束在父表数据被删除时触发对子表数据的级联删除操作。下面看看我们是如何将这些晦涩难懂的术语转换为一目了然的SQL代码的。

?

二、在更新数据库时使用外键约束

?

  正如前面介绍的一样,上一篇文章论述如何运用外键约束维护两个示例InnoDB表之间的关系:第一个表存储一些简单博客数据,而第二个表则存放这些博客的有关评论。这例子的巧妙之处在于,它给子表定义了一个外键约束,从而允许我们在博客文章被删除时自动地删除有关的所有评论。下面给出这两个表的定义,它们建立了一个一对多的关系:

  DROP TABLE IF EXISTS `test`.`blogs`;

  CREATE TABLE `test`.`blogs` (

  `id` INT(10) UNSIGNED AUTO_INCREMENT,

  `title` TEXT,

  `content` TEXT,

  `author` VARCHAR(45) DEFAULT NULL,

  PRIMARY KEY (`id`)

  ) ENGINE=InnoDB DEFAULT =utf8;

  DROP TABLE IF EXISTS `test`.`comments`;

  CREATE TABLE `test`.`comments` (

  `id` INT(10) UNSIGNED AUTO_INCREMENT,

  `blog_id` INT(10) UNSIGNED DEFAULT NULL,

  `comment` TEXT,

  `author` VARCHAR(45) DEFAULT NULL,

  PRIMARY KEY (`id`),

  KEY `blog_ind` (`blog_id`),

  CONSTRAINT `comments_ibfk_1` FOREIGNKEY(`blog_id`)REFERENCES`blogs` (`id`) ON UPDATE CASCADE

  ) ENGINE=InnoDB DEFAULT =utf8;

?除了给以上两个InnoDB表定义一些简单字段外,上述的代码还使用了一个外键约束,使得每当父表的“id”键更新时,表comments的相应内容也会级联更新。给父字段“id”定义约束的代码如下所示:

CONSTRAINT `comments_ibfk_1`FOREIGNKEY(`blog_id`)REFERENCES `blogs` (`id`) ONUPDATECASCADE

?

InnoDB引擎除了可以规定根据父表完成的操作对子表进行的级联更新以外,还可以执行其他的操作,包括“NOACTION”和“RESTRICT”,这样即使父表发生更新或者删除操作,也不会引起对子表的任何操作。

?

  现在,根据上面的MySQL表的定义,填充如下所示的数据:

INSERT INTO blogs (id, title,content,author)VALUES(NULL,Title of the first blog entry,Content of thefirstblogentry, Tom)

  INSERT INTO comments (id, blog_id, comment, author)VALUES(NULL,1,Commenting first blog entry, Susan Norton),(NULL,1,Commentingfirst blog entry, Rose)

?

然后,由于某种原因,我们更新了第一个博客数据,那么只要运行下列SQL语句,与该博客文章有关的所有评论也会随之自动更新:
UPDATE blogs SET id = 2, title = Title ofthefirstblogentry, content = Content of the first blogentry,author =JohnDoe WHERE id = 1
?这看起来非常不错,对吧?前面讲过,外键约束容许您将表之间的关系的维护工作委托给数据库层,这意味着编写与数据层交互的应用程序时可以省去不少的代码。

?

  此外,我们也可以触发级联删除操作,这与前面演示的情形非常类似。因此,下面我们继续使用早先定义的两个示例表来演示当某篇博客文章的数据被删除时,如何利用外键约束删除相应的评论。

?

三、不使用外键约束时的数据删除

?

  为了说明当父表数据被删除时,外键约束在维护数据库完整性方面发挥的作用,我们将重建前面的例子,这次使用MyISAM表。首先,我们需要定义数据表,具体代码如下所示:

DROP TABLE IF EXISTS `test`.`blogs`;

  CREATE TABLE `test`.`blogs` (

  `id` INT(10) UNSIGNED AUTO_INCREMENT,

  `title` TEXT,

  `content` TEXT,

  `author` VARCHAR(45) DEFAULT NULL,

  PRIMARY KEY (`id`)

  ) ENGINE=MyISAM DEFAULT =utf8;

  DROP TABLE IF EXISTS `test`.`comments`;

  CREATE TABLE `test`.`comments` (

  `id` INT(10) UNSIGNED AUTO_INCREMENT,

  `blog_id` INT(10) UNSIGNED DEFAULT NULL,

  `comment` TEXT,

  `author` VARCHAR(45) DEFAULT NULL,

  PRIMARY KEY (`id`)

  ) ENGINE=MyISAM DEFAULT =utf8;

?好了,我们已经建好了两个示例表,需要注意的是,它们使用的是默认的MyISAM数据库引擎,所以不支持外键约束。

?

  定义的这两个表构成了博客应用程序的数据层,接下来我们在其中填上一些数据,所用的代码如下所示:

INSERT INTO blogs (id, title,content,author)VALUES(NULL,Title of the first blog entry,Content of thefirstblogentry, Tom)

  INSERT INTO comments (id, blog_id, comment, author)VALUES(NULL,1,Commenting first blog entry, Susan Norton),(NULL,1,Commentingfirst blog en