博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
使用Trigger实现Cascading的功能
阅读量:5892 次
发布时间:2019-06-19

本文共 2474 字,大约阅读时间需要 8 分钟。

使用数据库的朋友大家想必都知道,如果想要维持“一堆多”数据表数据的一致性,必须做到以下几点:

1)插入时,外键必须包含于主表(“1”对多中“1”那个表)关联字段集合中。

2)删除时,主表关联字段被删除,其子表关联数据也一律自动被删除。

3)更新时,主表关联字段被更新,其子表关联数据也一律自动被更新。

其实要做到这三点,最简单的一个做法莫过于:

1)打开SQL Management Studio,成功登陆之后打开某个数据库(展开“+”节点),并且找到“Diagram”(关联图),导入所需要的表。

2)从主表(“1”)鼠标左键按住不放,拖拽到从表(“多”)的“外键”字段。在弹出的对话框中分别确定设置主表和从表即将关联的主键和外键。

3)右键生成的那个关联线,设置插入/删除更新时候的情况:

更新和删除规则有若干选项——其中“级联”就是本文开头所说的部分——“一荣俱荣,一损俱损”。

至于“插入”时的外键一致性,在“强制外键约束”默认设定为“是”可以得到体现(因为一旦创建了表关系,那么外键也就自动检查必须是隶属于主表关联字段的一个元素)。

其实我们也可以采用Trigger来完成同样的任务——所谓Trigger即“触发器”(可以理解成“事件”,是一个特定动作行为产生之后所带来的连锁反应)。

对于“插入”时外键约束(我们假设有Categories和Products表,其中Category主表,其Id关联于从表的Products的CategoryId)。Trigger可以这样写:

Create TRIGGER [dbo].[AutoCheck]   ON [dbo].[tb_Products]   for insertAS BEGIN    begin tran        --保存欲待插入的categoryId    declare @newCategoryId int    select @newCategoryId = categoryid from inserted    if(select count(*) from tb_Category where id=@newCategoryId)=1        begin            print('成功插入!')            commit        end    else        begin            print('插入失败!')            rollback tran        endEND

for insert其实可以看成是类似C#或者Basic.NET中的Inserting事件一样——我们知道,C#中某些控件(比如ASP.NET中GridView有Updating和Updated等事件,为了拦截插入的数据,我们可以使用该事件;该事件其中有一些参数自动记录欲插入数据表的新数据为我们所用并处理)。自然地,该“参数”在SQL中其实就是inserted表(每次插入记录,都会生成这张临时表,且里边只有一条记录)。我们从里边获取了categoryId并且在Category表中做搜寻——如果找到,说明存在(可以作为外键插入,否则不行)。因此还用了if……else进行判断。为了防止错误插入保持数据一致性,我们必须用“事物”(begin transcation……commit……rollback)代码块把SQL代码封装起来。

与此类似地还有delete和update——这里只给出delete的级联删除(使用Trigger完成)的示例代码:

Create TRIGGER [dbo].[CascadingDelete]    ON [dbo].[tb_Category]    for DELETE    AS    BEGIN        begin transaction            declare @primaryKey int            select @primaryKey = id from deleted            delete from tb_Products where CategoryId=@primaryKey       commit    END

总而言之,SQL实现的级联添加/删除或者更新其本质就是类似一个内部的触发器原理。

既然“级联”触发器完全可以被SQL内置的“关系图”取代,为何还是需要它呢?原因很简单——在某些情况下SQL是无法使用“级联删除/更新”滴。

假设有三张表Category,Products和Order。现在Category<==>order和Product<==>Order分别构成1对多关系(级联删除/更新),且Category和Products也构成一对多(级联删除/更新),此时如果使用“关系图”拉关系设置级联,将会触发“多重循环级联……”的问题,原因很简单,如果可以的话,那么删除一个Category将附带着删除对应的order内容;同时删除products内容;但是product又和order形成了级联删除关系,那么当删除一个category,级联删除products的同时,order也会被级联删除,等于删除了二次,数据会造成错误的

一般设置表级联关系时,不允许形成这种环形级联

但是如果你硬要这样做,必须破坏“环”——有两种做法:

1)删除Category和Orders的级联关系(推荐)。

2)删除Product和Orders级联关系,改用触发器在Products上实现(不推荐,因为Category没有必要直接控制Orders,一般删除Category必然删除Products,而删除products才导致order删除,因此第一种方案最好)。

转载于:https://www.cnblogs.com/ServiceboyNew/archive/2012/09/11/2680205.html

你可能感兴趣的文章
通过浏览器直接打开Android应用程序
查看>>
MVC调用SVC无法找到资源解决问题
查看>>
div加jquery实现iframe标签的功能
查看>>
iOS - Swift SQLite 数据库存储
查看>>
在线网站工具专帖
查看>>
使用SQL来分析数据库参数(一)(r10笔记第68天)
查看>>
Java数组深层复制
查看>>
Leetcode PHP题解--D28 884. Uncommon Words from Two Sentences
查看>>
Spring的依赖注入简介
查看>>
Web前端开发工具
查看>>
长连接数据实时推送方案(iOS)
查看>>
【译】在 JavaScript 中创建和填充任意长度的数组
查看>>
[技术地图]
查看>>
前端小团队建设(实用前端开发规范,推荐收藏)
查看>>
Flutter干货分享系列(1)Flutter基础
查看>>
TS学习一
查看>>
正则表达式
查看>>
springboot(三)——application.properties和application.yml是何时解析的
查看>>
iOS 一个比较完美的 Growing TextView
查看>>
dubbo+zookeeper+springmvc+mybatis分布式大型互联网企业架构
查看>>