牛腩新闻发布系统---外键约束下如何删除记录

一、为什么使用外键?

    查了些资料,八个字“保持完整性、一致性”,结合我之前做的重构机房收费系统,我的理解是“防止相关表中数据没有关联而变得孤立,最终导致数据冗余”,得出这个结论是上次让贾丽敏帮忙点系统时候我最深刻的感受,因为我的数据库关系图中辣么多张表却没有丝毫关系……

    既然官方解释是“完整性和一致性”,就先来说明一下:

    对于完整性和一致性,不少人都混为一谈了。

    完整性(integrity)更多是针对实际业务来说的,比如说一个职员ID,不能在一个表里是1,另一个表里却是2;数据库引擎一般通过主外键、触发器等来维护完整性的。

    一致性(consistency)是事务一个特征,要底层一点。举例来说,针对这个语句:update a set col1=1,col2=2 where id=1(更改一行数据的两列),数据库要保证在任何情况下,都绝不能出现只更改了col1,或只更改了col2的情况,这两列(col1和col2)要么一起被改,要么都没改。还包括内部的索引结构、内部数据字典等数据都要绝对保持一致。

    这个说明来自互联网,当然这一点还是要在项目中慢慢的去体会的。

 


二、外键约束下如何删除相关表中的信息?

牛腩新闻发布系统---外键约束下如何删除记录_第1张图片

    如上图所示,从左到右将其定义为1、2、3层,就像是我们三层里的U、B、D那样,一环扣一环,显然右侧是最深的一层,或者称之为底层;左侧是最浅的一层,或者称之为表层。

    很显然,删除表层的数据是很随意的,because它不会对其他层有任何影响,而删除中间层和底层的数据的时候,会影响上层建筑,就像我在王聚博客里看到的一个比喻,将其比喻为一座大厦,拆楼的时候是从上向下的,一层一层分解,如果直接去拆地下室,那么整个楼不就崩溃坍塌了吗?

 

     所以这就是第一种用于删除外键约束下的数据的方法的思想:逐层分解

    方法一:通过触发器实现

    就拿《牛腩新闻发布系统》的例子来说:

-- =============================================
-- Author:张振华
-- Create date:2015年月日:01:29
-- Description:	删除类别触发器
-- =============================================
ALTER TRIGGER trigCategoryDelete
   ON  Category
   instead of DELETE
AS 
BEGIN
   --声明一个
   declare @caId int 
   select @caId=id from deleted
   --删除评论(此处使用子查询,查询出的条件是多条,于是使用”in”而不是”=”)
   delete comment where newsId in (select newsId from news where caId=@caId)
   --删除新闻
   delete news where caId=@caId
   --删除类别
   delete category where id=@caId
END
GO

    这种方法的好处:不会破坏主外键的约束,保证完整性和一致性的同时,保证数据不会产生冗余,也不会造成误删而出现数据残缺的现象。同时,这种方法是在数据库里进行限制,使得在编程过程中直接使用该约束就OK,不用再次做其他逻辑上的约束。

 

   另一种用于删除外键约束下数据的思想是:连根拔起

   方法二:级联删除

    这种方法在重构机房的时候就接触过,只是迫于当时时间压力,把表中所有外键删除掉了,发现反而在程序中做好多逻辑上的约束,反而效果不怎么好,防不胜防。这次正好将这种方法学会。

所谓级联删除,就是删除主表记录同时删除从表中有外键关系的记录。

-- =============================================
-- Author:张振华
-- Create date:2015年7月5日
 -- Description:	级联删除举例
-- =============================================

create table category
(
id varchar(20) primary key,
name varchar(20) not null
)

create table news
(
--自增字段充当主键
id int identity(1,1) primary key,
title varchar(50) not null,
content varchar(50) not null,
--表news创建了外键caId 对应category表的主键id,同时声明了级联删除
caId varchar(20),
--on delete:删除级联
foreign key (caId) references category(id) on delete cascade
)

    这样建表之后,如果在表中category中添加“体育新闻”,将其删除之后,在news表中所有关于caId是“体育新闻”的记录都会被删除。

    由于是刚刚接触级联删除,和上面“逐层删除”相比,这种方法更像是将整栋楼“爆破”,从底层到上层建筑全部删掉,删除彻底,同时能保持数据的完整性以及一致性,我的感觉,有一点既是这样做的好处也是坏处就是,删除过于彻底,有点“连根拔起、一人犯罪,株连九族”的感觉,删除后没有冗余数据,但是过于彻底有可能会删除一些有用信息。

 

    最后介绍最简单的一种方法,我将其思想定义为:解除合约

   方法三:

    情景:如果需要删除底层的数据,但是表层的一些数据需要保留,也就是说仅仅需要删除一部分数据,怎么办?

暂时接触外键约束,将底层表中数据删除之后再加上外键约束,可能这样做会有种“脱掉裤子放屁”的感觉,但是对于仅仅删除一部分数据,尤其是底层数据的时候,这将是一种很好的方法,当然如果数据量大的话,这种方法还是不太好,但是至少这是解决问题的一种途径。

 


三、Summary

   扩展:

    在设置外键约束的条件下,删除会受到约束的限制,那么“增、改、查”会受到外键的约束吗?

我猜测,“改”会受到限制,其他两个不会,大家也可以尝试去做做这样的实验,当然仅仅是自己的猜测,有待验证。

 

   收获:

    在做重构机房收费系统的时候,就遗留了一个问题,设计数据库的过程中,因为主键冲突以及外键约束,导致我不得不删掉了当初设置的外键约束,而这样做的后果就是关系数据库的完整性和一致性遭到破坏。学习了牛腩的“删除外键约束条件下的数据”,让我解决掉了这个遗留问题,现在记录我的学习过程。




你可能感兴趣的:(牛腩新闻发布系统---外键约束下如何删除记录)