一、利用外键约束更新MySQL中的数据
现在,最流行的开源关系型数据库管理系统非MySQL莫属,而MySQL又支持多个存储引擎,其中默认的也是速度较快的存储引擎为MyISAM,对许多读者来说,在开发自己数据库驱动的web应用程序之前,可能已经使用了它很长一段时间了。
然而,有时候我们的项目可能需要额外的特性,例如需要处理外键约束,这时我们就需要用到其它类型的MySQL存储引擎。在这种情况下,InnoDB表将非常适合我们的要求,尽管在性能方面可能比MyISAM表要稍逊一筹。大家知道,使用InnoDB表外键约束主要优点之一就是,它使我们可以在数据库级别处理和维护多个表之间的关系,而无需将此任务推给与这些表打交道的应用程序的某些模块或者程序库。
当然,前面的几篇文章中,我们已经就IndoDB表的外键约束做过相应介绍,但是那里都是通过手工方式来操作外键约束的。在本文中,我们将说明如何在更新和删除父表中的数据时,如何通过脚本语言来触发相应子表的级联更新和删除操作。
这里,我们博客应用程序的数据层由两个表构成,在前面的示例中,对这些表的操作,都是通过手工键入SQL命令完成的,现在,我们将介绍如何使用PHP程序设计语言来完成这些工作。之所以选择PHP,是因为它目前MySQL最常见的搭配语言,下面我们以PHP 5为例来说明如何外键约束操作两个InnoDB表。 通过阅读本文,您将更加真切地体会到外键约束的特性。
现在,我们开始见证PHP 5和外键约束结合在一起所带来的威力吧!
#p#副标题#e#
二、以级联方式更新和删除数据库中的数据
古人云,温故而知新,那么先让我们来回顾一下前面学过的内容吧。之前,我们介绍过如何运用外键约束级联更新和删除存放博客文章评论的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 CHARSET=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` FOREIGN KEY (`blog_id`) REFERENCES `blogs` (`id`) ON DELETE CASCADE ON UPDATE CASCADE ) ENGINE=InnoDB DEFAULT CHARSET=utf8; |
上面的代码定义了两个表,需要注意一下第二个,因为它为“blog_id”字段规定了一个约束,所以当post表中的数据被更新和删除时,将触发相应的级联操作。
为了帮您理解这一过程,我们可以在表中填上一些数据,这时可以通过SQL语句INSERT来完成,如下:
INSERT INTO blogs (id, title, content, author) VALUES (NULL,'Title of the first blog entry', 'Content of the first blog entry', 'IAN') INSERT INTO comments (id, blog_id, comment, author) VALUES (NULL, 1, 'Commenting first blog entry', 'Tom'), (NULL, 1, 'Commenting first blog entry', 'Rose') |
现在,我们唯一的一条博客数据已经有了两条评论数据,如果由于任何原因需要更新博客及其评论数据的话,可以通过下列命令完成:
UPDATE blogs SET id = 2, title = 'Title of the first blog entry', content = 'Content of the first blog entry', author = 'John Doe' WHERE id = 1 |
这看起来非常简单,但是,如果我说将博客数据连同相应的评论数据一同删除会更加简单,您能会相信吗?如果不信的话,请看下面的SQL语句:
DELETE FROM blogs WHERE id = 2 |
如您所见,这就是删除指定博客及其评论所需的全部SQL代码,这足以证明通过外键约束维护两个InnoDB表的完整性到底有多么的方便。
迄今为止,我们已经简单回顾之前所学的内容,接下来,我们将继续探索这些表的约束的各种优点。 就像本文开头部分介绍的那样,我们将开始讲解如何通过PHP 5内置的MySQL抽象类来生成对我们的示例表的级联更新。
#p#副标题#e#
三、利用PHP 5以级联方式更新数据库
好了,现在开始详细介绍如何使用流行的服务器端脚本语言PHP 5来以级联方式更新我们的示例表。为此,我们需要编写允许我们访问上面定义的InnoDB表的代码,就本例而言,我们使用PHP 5的MySQL抽象类来达此目的。下面给出具体的代码:
class MySQL { private $result = NULL; private $link = NULL; //连接到MySQL public function __construct($host, $user, $password, $database) { if (FALSE === ($this->link = mysqli_connect($host, $user, $password, $database))) { throw new Exception('Error : ' . mysqli_connect_error()); } } //执行查询 public function query($query) { if (is_string($query) AND empty($query) === FALSE) { if (FALSE === ($this->result = mysqli_query($this->link, $query))) { throw new Exception('Error performing query ' . $query . ' Error message :' .mysqli_error($this->link)); } } } //从结果集返回数据 public function fetch() { if (FALSE === ($row = mysqli_fetch_object($this->result))) { mysqli_free_result($this->result); return FALSE; } return $row; } //获取插入ID public function getInsertID() { return mysqli_insert_id($this->link); } //结果集中的行数 public function countRows() { if ($this->result !== NULL) { return mysqli_num_rows($this->result); } } //关闭数据库连接 function __destruct() { mysqli_close($this->link); } } |
如上所示,上面定义的MySQL抽象类十分简单,它提供了许多常用的方法,用于执行查询、统计结果集行数以及获取插入ID。需要格外注意的是,这个类内部使用了PHP扩展mysqli来跟MySQL打交道,所以整体看来是很容易理解的。
好了,我们已经定义了一个可以用于跟MySQL数据库相交互的PHP 5类,现在我们要做的就是利用它的API对前面定义的InnoDB表执行级联更新。
#p#副标题#e#
四、MySQL抽象类
现在,为了演示如何使用上述的MySQL类级联更新前文中的数据表,我们需要重新定义那两个表,以便使其只能执行这些更新的操作。这里是它们的定义,这两个表将作为我们的示例博客应用程序的数据层:
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 CHARSET=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` FOREIGN KEY (`blog_id`) REFERENCES `blogs` (`id`) ON UPDATE CASCADE ) ENGINE=InnoDB DEFAULT CHARSET=utf8; |
如上所述,通过给最后一个表中的blog_id字段规定外键约束,我们已经把两个表联系在了一起,接下来让我们使用前面定义的MySQL抽象类给它们填入必要的数据。
#p#副标题#e#
我们假设这个类被单独放入一个名为mysqlclass.php文件中,下面的脚本将向blog表中插入单篇博客文章,并向comments表中插入两则评论:
require_once 'mysqlclass.php'; $db = new MySQL('host', 'user', 'password', 'test'); //在blogs数据库表中插入新数据 $db->query("INSERT INTO blogs (id, title, content, author) VALUES (NULL,'Title of the first blog entry', 'Content of the first blog entry', 'IAN')"); $insid = $db->getInsertID(); //在comments数据库表中插入新评论 $db->query("INSERT INTO comments (id, blog_id, comment, author) VALUES (NULL, $insid, 'Commenting first blog entry', 'Tom'), (NULL, $insid, 'Commenting first blog entry', 'Rose')"); |
虽然我们的这个MySQL类能够抽象地访问数据库,但是相应的SQL查询还得手工编写。同时,它正好可以使我们可以展示每当第一个表中的数据更新时,如何使用该类来更新与第一个数据表相关的评论。
执行该级联更新操作的代码片断如下所示:
//更新blogs表中的数据(comments表中的有关数据将自动更新) $db->query("UPDATE blogs SET id = 2, title = 'Title of the first blog entry', content = 'Content of the first blog entry', author = 'John Doe' WHERE id = 1"); |
尽管另外添加了一个与上述InnoDB表打交道的抽象类,但是触发级联更新所需的SQL代码仍然保持高度简洁。这说明,各表之间的关系的完整性仍然是在数据库级别进行维护的,而不是由PHP 5应用程序所维护的。
五、小结
到目前为止,我们详细讲解了如何通过PHP 5内置的抽象类使用外键约束来更新两个InnoDB表中的数据。 我们希望本文能够对您利用服务器端脚本使用外键约束时能够有所启发。在后面的文章中,我们将继续探讨外键约束有关的内容。