一 什么是触发器

1.1  触发器的概念

  触发器(trigger)是SQL server来保证数据完整性的一种方法,它是与表事件相关的特殊的存储过程,它的执行是由事件来触发,当对一个表进行操作( insert,delete, update)时就会激活它执行。触发器经常用于加强数据的完整性约束和业务规则等。

触发器和存储过程的区别:

  触发器与存储过程的区别是运行方式的不同,触发器在执行T-SQL语句时自动触发执行,而存储过程需要用户,应用程序或者触发器来显式地调用并执行。

1.2  触发器的优点和使用场景

 1.触发器是自动的。当对表中的数据做了任何修改之后立即被激活。

 2.级联修改数据库中所有相关的表,自动触发其它与之相关的操作(删除角色,所有使用该角色的用户设置为默认的低权限角色)

 3.触发器可以强制限制。这些限制比用CHECK约束所定义的更复杂。与CHECK约束不同的是,触发器可以引用其他表中的列。

4.返回自定义的错误消息。CHECK约束无法返回信息,而触发器可以

5.触发器可以调用更多的存储过程

二 DML触发器的工作原理

inserted表和deleted表对照: 

修改操作记录 inserted表 deleted表
增加(insert)记录 存放新增的记录 ............
删除(deleted)记录 .............. 存放被删除的记录
修改(update)记录 存放更新后的记录 存放更新前的记录

执行顺序: 

  after触发器被触发时,先建立临时的inserted表和deleted表--->执行用户的sql代码--->执行触发器中的代码。
  instead of触发器被触发时,先建立临时的inserted表和deleted表--->直接触发instead of触发器(用触发器中代码替代用户的sql代码,用户的sql代码不执行)。

三 使用DML触发器

准备测试数据:

--创建用户表
create table UserInfo(
userId int identity(1,1) primary key,
userName nvarchar (20),
userGender char(2),
userRoleId int not null
) --创建角色表
create table RoleInfo(
roleId int identity(1,1) primary key,
roleName nvarchar(20)
)

3.1  创建insert触发器

作用:插入一个新userinfo,统计userinfo个数

--创建insert触发器
create trigger trig_insertUser on userinfo
after insert
as
begin
if object_id(N'userSum',N'U') is null --判断userSum表是否存在
create table userSum (numbers int default(0));
declare @userCount int;
select @userCount=count(*) from userinfo;
if not exists(select * from userinfo) --判断userInfo表是否有数据
insert into userSum (numbers) values(0);
update userSum set numbers=@userCount;--插入新用户后更新统计数据
end --执行
insert into userinfo (username,usergender,userroleid) values('zs','男',1);
select numbers as '用户人数' from userSum
insert into userinfo (username,usergender,userroleid) values('ls','男',1);
select numbers as '用户人数' from userSum
insert into userinfo (username,usergender,userroleid) values('ww','男',2);
select numbers as '用户人数' from userSum

执行结果:

userSum在插入数据时自动更新,应该禁止用户向其中直接插入数据

--创建禁止插入的触发器
create trigger trig_insertForbidden on userSum
after insert
as
begin
RAISERROR('禁止直接插入记录,操作被禁止',1,1);
rollback tran
end --执行
insert into userSum (numbers) values(10)

结果如下:

3.2  创建delete触发器

作用:删除角色,把使用该角色的用户设置为“默认角色”

--删除角色的delete触发器
create trigger trig_deleterole on roleinfo
after delete
as
begin
declare @roleid int;
select @roleid= roleid from deleted;--删除的角色Id
select rolename as 删除的角色 from deleted;--删除的角色
update userinfo set userroleid=1 where userroleid=@roleid --修改使用该角色的用户的角色为默认角色
end --执行
delete from roleinfo where roleid=2

  角色表:

 

删除角色2前用户表:                  删除角色2后的用户表 :                                                                                                                  

  

3.3  创建UPDATE触发器

  update触发器是当用户在指定表上执行update语句时被调用被调用,这种类型的触发器用来约束用户对数据的修改。update触发器可以执行两种操作:更新前的记录存储在deleted表中,更新后的记录存储在inserted表中。

--更新用户的update触发器
create trigger trig_userupdate on userinfo
after update
as
begin
select username as 更新前的用户, usergender as 性别 from deleted --更新前
select username as 更新后的用户, usergender as 性别 from inserted--更新后
end --执行
update userinfo set username='newzs',usergender='女' where userid=23 --注:编号23是一个用户名为'zs',性别'男'的用户

执行结果:

3.4  创建instead of 触发器

作用:执行删除操作时用逻辑删除替代

  在删除用户时,我们通常不希望真正去把用户信息删除掉,而是设置一个删除标记,表示该用户已被删除了(逻辑删除)。这里在用户表中添加“isDeleted”字段<bit类型>,false表示未删除,true表示已删除,表结构如下:

  创建触发器的代码

--创建instead of触发器
create trigger trig_insteadofdel on userinfo
instead of delete
as
begin
declare @userid int;
select @userid=userid from deleted ;
update userinfo set isdeleted=1 where userid=@userid;
select * from deleted;--逻辑删除前
select * from userinfo where userid=@userid;--逻辑删除后
end --执行
delete userinfo where userid=23

  执行结果(可以看出并没有真正去执行删除操作,而是被逻辑删除替代了):

3.5  嵌套触发器介绍

    如果一个触发器在执行操作时调用了另外一个触发器,而这个触发器又接着调用了下一个触发器,那么就形成了嵌套触发器。嵌套触发器在安装时就被启用,但是可以使用系统存储过程sp_configure禁用和重新启用嵌套触发器。

  嵌套触发器不一定要形成一个环,它可以 T1->T2->T3...这样一直触发下去,最多允许嵌套 32 层。如果嵌套的次数超过限制,那么该触发器将被终止,并回滚整个事务,使用嵌套触发器需要注意以下几点:

  • 默认情况下,嵌套触发器配置选项是开启的。
  • 在同一个触发器事务中,一个嵌套触发器不能被触发两次。
  • 由于触发器是一个事务,如果在一系列嵌套触发器的任意层次中发生错误,则整个事务都将取消,而且所有数据回滚。

嵌套是用来保持整个数据库的完整性的重要功能,但有时可能需要禁用嵌套,如果禁用了嵌套,那么修改一个触发器的实现不会再触发该表上的任何触发器。在下述情况下,需要禁用嵌套触发器:

  • 嵌套触发要求复杂而有理论的设计,级联修改可能会修改用户不想涉及的数据。
  • 在一系列嵌套触发器中的任意点的时间修改操作都会触发一些触发器,尽管这时数据库提供很强的保护功能,但如果以特定的顺序更新表,就会产生问题。

使用下列语句禁用嵌套和再次启用嵌套:

--禁用嵌套
exce sp_configure 'nested triggers',0;
--启用嵌套
exce sp_configure 'nested triggers',1;

3.6  递归触发器

  触发器的递归是指一个触发器从其内部再一次激活该触发器。例如update操作激活的触发器内部还有一条数据表的更新语句,那么这个更新语句就有可能激活这个触发器本身,当然,这种递归的触发器内部还会有判断语句,只有一定情况下才会执行那个T_SQL语句,否则就成为无线调用的死循环了。

SqlServer中的递归触发器包括两种:直接递归和间接递归。

  • 直接递归:触发器被触发后并执行一个操作,而该操作又使用一个触发器再次被触发。
  • 间接递归:触发器被触发并执行一个操作,而该操作又使另一个表中的某个触发器被触发,第二个触发器使原始表得到更新,从而再次触发第一个触发器。

默认情况下,递归触发器选项是禁用的。递归触发器最多只能递归16层,如果递归中的第16个触发器激活了第17个触发器,则结果与发布的rollback命令一样,所有数据都将回滚。

我们举例解释如下,假如有表1、表2名称分别为 T1、T2,在 T1、T2 上分别有触发器 G1、G2。

  • 间接递归:对 T1 操作从而触发 G1,G1 对 T2 操作从而触发 G2,G2 对 T1 操作从而再次触发 G1...
  • 直接递归:对 T1 操作从而触发 G1,G1 对 T1 操作从而再次触发 G1...

设置直接递归:

默认情况下是禁止直接递归的,要设置为允许有两种方法:

  • T-SQL:exec sp_dboption 'dbName', 'recursive triggers', true;
  • EM:数据库上点右键->属性->选项。

四 管理触发器

4.1  查看触发器

1  查看数据库中所有的触发器

--查看数据库中所有的触发器
use 数据库名
go
select * from sysobjects where xtype='TR'

sysobjects 保存着数据库的对象,其中 xtype 为 TR 的记录即为触发器对象。在 name 一列,我们可以看到触发器名称。

2  sp_helptext 查看触发器内容

use 数据库名
go
exec sp_helptext '触发器名称'

将会以表的样式显示触发器内容。

除了触发器外,sp_helptext 还可以显示 规则、默认值、未加密的存储过程、用户定义函数、视图的文本。

3  sp_helptrigger 用于查看触发器的属性

  sp_helptrigger 有两个参数:第一个参数为表名;第二个为触发器类型,为 char(6) 类型,可以是 INSERT、UPDATE、DELETE,如果省略则显示指定表中所有类型触发器的属性。

use 数据库名
go
exec sp_helptrigger tableName

4.2  禁用启用触发器

  禁用:alter table 表名 disable trigger 触发器名称
  启用:alter table 表名 enable trigger 触发器名称

  如果有多个触发器,则各个触发器名称之间用英文逗号隔开。

  如果把“触发器名称”换成“ALL”,则表示禁用或启用该表的全部触发器。

4.3  修改触发器

--修改触发器语法
ALTER TRIGGER trigger_name
ON table_name
[ WITH ENCRYPTION ]
FOR {[DELETE][,][INSERT][,][UPDATE]}
AS
sql_statement;

4.4  删除触发器

 --语法格式:
DROP TRIGGER { trigger } [ ,...n ]
参数:
trigger: 要删除的触发器名称
n:表示可以删除多个触发器的占位符

参考文章:

  1、http://www.cnblogs.com/wangprince2017/p/7827091.html

  2、http://www.cnblogs.com/wangprince2017/p/7827091.html

Sqlserver中的触发器的更多相关文章

  1. SqlServer 中的触发器

    SqlServer 触发器实现多表之间同步增加.删除与更新 定义: 何为触发器?在SQL Server里面也就是对某一个表的一定的操作,触发某种条件,从而执行的一段程序.触发器是一个特殊的存储过程. ...

  2. 知方可补不足~sqlserver中触发器的使用

    回到目录 触发器在过去的10年中,即存储过程和ado.net称霸江湖期间是那么的重要,而现在,trigger显得不是那么必要的,我们很少将复杂的业务写在SQL里,当然也会没有机会写到trigger里了 ...

  3. Sqlserver中存储过程,触发器,自定义函数(二)

    Sqlserver中存储过程,触发器,自定义函数: 自定义函数:1.函数类型:2.函数的参数和返回值: 1.函数类型:标量值函数,返回的是一个标量值表值函数:内联表值函数:多语句表值函数. 标量值函数 ...

  4. Sqlserver中存储过程,触发器,自定义函数(一)

    Sqlserver中存储过程,触发器,自定义函数 1.存储过程有关内容存储过程的定义:存储过程的分类:存储过程的创建,修改,执行:存储过程中参数的传递,返回与接收:存储过程的返回值:存储过程使用游标. ...

  5. Sqlserver中存储过程,触发器,自定义函数

    Sqlserver中存储过程,触发器,自定义函数: 1. 触发器:是针对数据库表或数据库的特殊存储过程,在某些行为发生的时候就会被激活 触发器的分类: DML触发器:发生在数据操作语言执行时触发执行的 ...

  6. C#批量插入数据到Sqlserver中的四种方式

    我的新书ASP.NET MVC企业级实战预计明年2月份出版,感谢大家关注! 本篇,我将来讲解一下在Sqlserver中批量插入数据. 先创建一个用来测试的数据库和表,为了让插入数据更快,表中主键采用的 ...

  7. SQLSERVER中的假脱机spool

    SQLSERVER中的假脱机spool 我发现网上对于假脱机的解释都非常零散,究竟假脱机是什么? 这几天在家里研究了一下,收集了很多网上的资料 假脱机是中文的翻译,而英文的名字叫做 spool 在徐老 ...

  8. SqlServer基础之(触发器)

    概念:   触发器(trigger)是SQL server 提供给程序员和数据分析员来保证数据完整性的一种方法,它是与表事件相关的特殊的存储过程,它的执行不是由程序调用,也不是手工启动,而是由事件来触 ...

  9. (转)笔记320 SQLSERVER中的加密函数 2013-7-11

    1 --SQLSERVER中的加密函数 2013-7-11 2 ENCRYPTBYASYMKEY() --非对称密钥 3 ENCRYPTBYCERT() --证书加密 4 ENCRYPTBYKEY() ...

随机推荐

  1. HDU4035 Maze 【树形DP】【期望DP】

    题目分析: 以前一直不会这个方法, 我好菜啊. 转移分为三个部分,一个是直接成功,一个是转移到E1,还有一个是转移到自己周围的一圈儿点. 如果是叶子那么只能转移到父亲,如果不是叶子可以把非叶子的转移代 ...

  2. hdu 5877 Weak Pair (Treap)

    链接:http://acm.hdu.edu.cn/showproblem.php?pid=5877 题面; Weak Pair Time Limit: 4000/2000 MS (Java/Other ...

  3. Codeforces Global Round 2 D. Frets On Fire (动态开点线段树,沙雕写法)

    题目链接:D. Frets On Fire 思路:明明可以离散化+二分写,思路硬是歪到了线段树上,自闭了,真实弟弟,怪不得其他人过得那么快 只和查询的区间长度有关系,排完序如果相邻的两个点的差值小于等 ...

  4. wstngfw中使用Viscosity连接OpenV-P-N服务器

    wstngfw中使用Viscosity连接OpenV-P-N服务器 在本例中,将假设以下设置: 站点 A 站点 B 名称 Beijing Office(北京办公室) 名称 Shenzheng Offi ...

  5. DNSCrypt

    DNSCrypt 来源 https://www.cnblogs.com/qiudabai/articles/9219840.html https://www.opendns.com/about/inn ...

  6. Java 异常处理流程

    Java 异常处理流程 ============== End

  7. Python面试指南

    1.Python基本语法 1.@staticmethod 和 @classmethod Python中有三种方法,实例方法.类方法(@classmethod).静态方法(@staticmethod). ...

  8. cf1061E Politics (费用流)

    看到数据范围,考虑网络流..但考的时候完全不知道怎么建图 考虑流量表示选的点个数,费用表示选点的收益,跑最大费用最大流 那么我用一个点x表示某树中的询问点x,刨去它子孙询问点的子树后的子树 对于树1, ...

  9. bzoj1226/luogu2157 学校食堂 (状压dp)

    我们先约定:(左) 窗口_人人人人人 (右) 可以发现,我们只需要知道最靠左的还没打饭的人 以及它身后7个人的状态 以及上一个打饭的人是谁 因为他左面的就都打过了 右面7个人以后肯定还没打 可以设f[ ...

  10. 20165223《Java程序设计》第八周Java学习总结

    教材学习内容总结 第12章-JAVA多线程机制 要点 Java中的线程 Thread类与线程的创建 线程的常用方法 线程同步 协调同步的线程 线程联合 GUI线程 计时器线程 教材学习中的问题和解决过 ...