标签:
一、为什么使用外键?
查了些资料,八个字“保持完整性、一致性”,结合我之前做的重构机房收费系统,我的理解是“防止相关表中数据没有关联而变得孤立,最终导致数据冗余”,得出这个结论是上次让贾丽敏帮忙点系统时候我最深刻的感受,因为我的数据库关系图中辣么多张表却没有丝毫关系……
既然官方解释是“完整性和一致性”,就先来说明一下:
对于完整性和一致性,不少人都混为一谈了。
完整性(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
扩展:
在设置外键约束的条件下,删除会受到约束的限制,那么“增、改、查”会受到外键的约束吗?
我猜测,“改”会受到限制,其他两个不会,大家也可以尝试去做做这样的实验,当然仅仅是自己的猜测,有待验证。
收获:
在做重构机房收费系统的时候,就遗留了一个问题,设计数据库的过程中,因为主键冲突以及外键约束,导致我不得不删掉了当初设置的外键约束,而这样做的后果就是关系数据库的完整性和一致性遭到破坏。学习了牛腩的“删除外键约束条件下的数据”,让我解决掉了这个遗留问题,现在记录我的学习过程。
版权声明:本文为博主原创文章,未经博主允许不得转载。
标签:
原文地址:http://blog.csdn.net/zzh920625/article/details/46765955