牛腩新闻公布系统---外键约束下怎样删除记录

一、为什么使用外键?

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

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

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

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

    一致性(consistency)是事务一个特征,要底层一点。

举例来说,针对这个语句:update a set col1=1,col2=2 where id=1(更改一行数据的两列)。数据库要保证在不论什么情况下,都绝不能出现仅仅更改了col1,或仅仅更改了col2的情况,这两列(col1和col2)要么一起被改,要么都没改。还包含内部的索引结构、内部数据字典等数据都要绝对保持一致。

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

 


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


    如上图所看到的,从左到右将其定义为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

   扩展:

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

我推測。“改”会受到限制。其它两个不会。大家也能够尝试去做做这种实验,当然不过自己的推測,有待验证。

 

   收获:

    在做重构机房收费系统的时候。就遗留了一个问题,设计数据库的过程中。由于主键冲突以及外键约束,导致我不得不删掉了当初设置的外键约束,而这样做的后果就是关系数据库的完整性和一致性遭到破坏。

学习了牛腩的“删除外键约束条件下的数据”,让我解决掉了这个遗留问题。如今记录我的学习过程。




posted on 2017-06-16 16:09  wgwyanfs  阅读(278)  评论(0编辑  收藏  举报

导航