如今,許多關(guān)系型數(shù)據(jù)庫管理系統(tǒng)都提供了外鍵約束這一強(qiáng)大的功能特性,它能夠幫助我們自動(dòng)地觸發(fā)指定的動(dòng)作,諸如刪掉、更新數(shù)據(jù)庫表的記錄等,從而維護(hù)各數(shù)據(jù)庫表之間預(yù)定義的關(guān)系。本文將演示如何在MySQL中利用外鍵約束以級(jí)聯(lián)方式刪除數(shù)據(jù)。 對(duì)于PHP開發(fā)人員來說,在MySQL中使用InnoDB表時(shí)可以利用外鍵約束提供的許多的便利之處,盡管MySQL宣布將來的版本支持MyISAM表。本文將演示當(dāng)更新和刪除父表數(shù)據(jù)時(shí)如何維護(hù)一個(gè)數(shù)據(jù)庫的完整性。 一、簡介 在上一篇文章中,我們講解了如何在MySQL的InnoDB表中結(jié)合使用外鍵約束,即當(dāng)父表中的數(shù)據(jù)更新的同時(shí)如何觸發(fā)對(duì)子表數(shù)據(jù)的級(jí)聯(lián)更新操作。說老實(shí)話,從字面上描述級(jí)聯(lián)更新過程有些令人費(fèi)解,如果通過SQL代碼來演示的話則要輕松得多。那么,我們先用文章做簡單表述,然后給出具體的代碼。在最簡單的情況下,這個(gè)過程首先要?jiǎng)?chuàng)建一個(gè)父表和一個(gè)子表,在子表中定義一個(gè)外鍵,然后規(guī)定當(dāng)父表的數(shù)據(jù)更新時(shí)將發(fā)生什么動(dòng)作。 使用外鍵約束的主要好處是,我們可以在數(shù)據(jù)庫級(jí)別很輕松地對(duì)表之間的關(guān)系進(jìn)行處理,而無需在與數(shù)據(jù)層交互的應(yīng)用程序內(nèi)部實(shí)現(xiàn)這些邏輯。值得一提的是,這對(duì)于性能來說,可能會(huì)有一些損失,尤其是程序規(guī)模較大的時(shí)候。當(dāng)然,數(shù)據(jù)庫性能問題不在本文的討論范圍之內(nèi),下面我們演示如何使用外鍵約束在父表數(shù)據(jù)被刪除時(shí)觸發(fā)對(duì)子表數(shù)據(jù)的級(jí)聯(lián)刪除操作。下面看看我們是如何將這些晦澀難懂的術(shù)語轉(zhuǎn)換為一目了然的SQL代碼的。 二、在更新數(shù)據(jù)庫時(shí)使用外鍵約束 正如前面介紹的一樣,上一篇文章論述如何運(yùn)用外鍵約束維護(hù)兩個(gè)示例InnoDB表之間的關(guān)系:第一個(gè)表存儲(chǔ)一些簡單博客數(shù)據(jù),而第二個(gè)表則存放這些博客的有關(guān)評(píng)論。這例子的巧妙之處在于,它給子表定義了一個(gè)外鍵約束,從而允許我們?cè)诓┛臀恼卤粍h除時(shí)自動(dòng)地刪除有關(guān)的所有評(píng)論。下面給出這兩個(gè)表的定義,它們建立了一個(gè)一對(duì)多的關(guān)系: 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; 除了給以上兩個(gè)InnoDB表定義一些簡單字段外,上述的代碼還使用了一個(gè)外鍵約束,使得每當(dāng)父表的“id”鍵更新時(shí),表comments的相應(yīng)內(nèi)容也會(huì)級(jí)聯(lián)更新。給父字段“id”定義約束的代碼如下所示: CONSTRAINT `comments_ibfk_1`FOREIGNKEY(`blog_id`)REFERENCES `blogs` (`id`) ONUPDATECASCADEInnoDB引擎除了可以規(guī)定根據(jù)父表完成的操作對(duì)子表進(jìn)行的級(jí)聯(lián)更新以外,還可以執(zhí)行其他的操作,包括“NOACTION”和“RESTRICT”,這樣即使父表發(fā)生更新或者刪除操作,也不會(huì)引起對(duì)子表的任何操作。 現(xiàn)在,根據(jù)上面的MySQL表的定義,填充如下所示的數(shù)據(jù): 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)然后,由于某種原因,我們更新了第一個(gè)博客數(shù)據(jù),那么只要運(yùn)行下列SQL語句,與該博客文章有關(guān)的所有評(píng)論也會(huì)隨之自動(dòng)更新: UPDATE blogs SET id = 2, title = Title ofthefirstblogentry, content = Content of the first blogentry,author =JohnDoe WHERE id = 1這看起來非常不錯(cuò),對(duì)吧?前面講過,外鍵約束容許您將表之間的關(guān)系的維護(hù)工作委托給數(shù)據(jù)庫層,這意味著編寫與數(shù)據(jù)層交互的應(yīng)用程序時(shí)可以省去不少的代碼。 此外,我們也可以觸發(fā)級(jí)聯(lián)刪除操作,這與前面演示的情形非常類似。因此,下面我們繼續(xù)使用早先定義的兩個(gè)示例表來演示當(dāng)某篇博客文章的數(shù)據(jù)被刪除時(shí),如何利用外鍵約束刪除相應(yīng)的評(píng)論。 三、不使用外鍵約束時(shí)的數(shù)據(jù)刪除 為了說明當(dāng)父表數(shù)據(jù)被刪除時(shí),外鍵約束在維護(hù)數(shù)據(jù)庫完整性方面發(fā)揮的作用,我們將重建前面的例子,這次使用MyISAM表。首先,我們需要定義數(shù)據(jù)表,具體代碼如下所示: 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; 好了,我們已經(jīng)建好了兩個(gè)示例表,需要注意的是,它們使用的是默認(rèn)的MyISAM數(shù)據(jù)庫引擎,所以不支持外鍵約束。 定義的這兩個(gè)表構(gòu)成了博客應(yīng)用程序的數(shù)據(jù)層,接下來我們?cè)谄渲刑钌弦恍?shù)據(jù),所用的代碼如下所示: 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) 實(shí)際上,以上代碼片斷模擬了博客應(yīng)用程序運(yùn)行時(shí),我們發(fā)布了博客并有人張貼評(píng)論時(shí),程序在表blogs中插入一篇博客文章的有關(guān)數(shù)據(jù),并在子表中插入有關(guān)評(píng)論的過程。現(xiàn)在,如果我們刪除了這篇博客,那么有關(guān)的評(píng)論也應(yīng)該隨之刪除。 但是,我們?cè)撊绾稳プ瞿?別急,下面我們以SQL語句為例說明如何完成此任務(wù): DELETE FROM blogs WHERE id = 1 DELETE FROM comments WHERE blog_id = 1當(dāng)然,在實(shí)際情況下,我們應(yīng)該通過服務(wù)器端語言來執(zhí)行這兩個(gè)刪除語句,而不是使用原始的SQL命令;但是這里只是舉例之用,就不用考慮這么多了。 我想您現(xiàn)在已經(jīng)弄明白了使用MyISAM表時(shí)如何刪除博客數(shù)據(jù),以及有關(guān)的評(píng)論。因此,接下來我們將重新構(gòu)建這個(gè)例子,不過這次我們將讓數(shù)據(jù)表使用InnoDB存儲(chǔ)引擎和一個(gè)簡單的外鍵約束。 四、使用外鍵約束時(shí)的數(shù)據(jù)刪除 恰如您可以使用外鍵約束級(jí)聯(lián)更新數(shù)據(jù)一樣,InnoDB表還支持級(jí)聯(lián)刪除,這對(duì)于維護(hù)那些具有特定關(guān)系的數(shù)據(jù)表的一致性極為有用。 下面我們舉例說明,現(xiàn)在重新定義兩個(gè)表,如下所示: 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 DELETE CASCADE ) ENGINE=InnoDB DEFAULT =utf8;現(xiàn)在,組成我們虛構(gòu)的博客應(yīng)用程序的數(shù)據(jù)層的兩個(gè)表blogs和comments將使用InnoDB存儲(chǔ)引擎。這意味著,它們能利用外鍵約束來刪除與某博客有關(guān)的所有評(píng)論,當(dāng)該博客被刪除的時(shí)候。 引起級(jí)聯(lián)刪除的SQL語句如下所示: CONSTRAINT `comments_ibfk_1`FOREIGNKEY(`blog_id`)REFERENCES `blogs` (`id`) ONDELETECASCADE 現(xiàn)在,由于這個(gè)約束已經(jīng)施加于blog表的“id”字段,所以在刪除博客的同時(shí)清除有關(guān)評(píng)論將非常簡單,就像運(yùn)行一個(gè)DELETE命令一樣,具體如下所示: DELETE FROM blogs WHERE id = 1 我們看到,現(xiàn)在事情變得簡單多了。從這個(gè)例子您就可以想象得出,當(dāng)數(shù)據(jù)層使用利用外鍵約束在數(shù)據(jù)庫級(jí)別維護(hù)各表之間關(guān)系的完整性和一致性的數(shù)據(jù)表的時(shí)候,開發(fā)與這樣的數(shù)據(jù)層交互的應(yīng)用程序是多么的簡單。 五、小結(jié) 在本文中,我們首先回顧了如何在數(shù)據(jù)表更新時(shí)使用外鍵約束,然后為讀者詳細(xì)介紹了當(dāng)父表執(zhí)行了刪除操作時(shí),如何使用外鍵約束觸發(fā)對(duì)子表的級(jí)聯(lián)刪除操作。您也許還記得,在上一篇文章中我們介紹了如何在父表更新時(shí)讓子表觸發(fā)相同的操作,那么能不能用外鍵約束同時(shí)處理刪除和更新操作呢?您可能已經(jīng)猜到了,答案是肯定的,具體的介紹請(qǐng)見下一篇文章。 |
|