SqlServer基础之(触发器)

SqlServer基础之(触发器)

 

概念:程序员

  触发器(trigger)是SQL server 提供给程序员和数据分析员来保证数据完整性的一种方法,它是与表事件相关的特殊的存储过程,它的执行不是由程序调用,也不是手工启动,而是由事件来触发,当对一个表进行操做( insert,delete, update)时就会激活它执行。触发器常常用于增强数据的完整性约束和业务规则等。 触发器能够从 DBA_TRIGGERS ,USER_TRIGGERS 数据字典中查到。sql

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

  触发器与存储过程的区别是运行方式的不一样,触发器不能执行EXECUTE语句调用,而是在用户执行Transact-SQL语句时自动触发执行而存储过程须要用户,应用程序或者触发器来显示地调用并执行。服务器

一:触发器的优势

 1.触发器是自动的。当对表中的数据作了任何修改以后当即被激活。架构

 2.触发器能够经过数据库中的相关表进行层叠修改。ide

 3.触发器能够强制限制。这些限制比用CHECK约束所定义的更复杂。与CHECK约束不一样的是,触发器能够引用其余表中的列。函数

二:触发器的做用

 触发器的主要做用就是其可以实现由主键和外键所不能保证的复杂参照完整性和数据的一致性,它可以对数据库中的相关表进行级联修改,提升比CHECK约束更复杂的的数据完整性,并自定义错误消息。触发器的主要做用主要有如下接个方面:post

  1. 强制数据库间的引用完整性
  2. 级联修改数据库中全部相关的表,自动触发其它与之相关的操做
  3. 跟踪变化,撤销或回滚违法操做,防止非法修改数据
  4. 返回自定义的错误消息,约束没法返回信息,而触发器能够
  5. 触发器能够调用更多的存储过程

三:触发器的分类

 SqlServer包括三种常规类型的触发器:DML触发器、DDL触发器和登陆触发器。测试

1.DML(数据操做语言,Data Manipulation Language)触发器

 DML触发器是一些附加在特定表或视图上的操做代码,当数据库服务器中发生数据操做语言事件时执行这些操做。SqlServer中的DML触发器有三种:

  1. insert触发器:向表中插入数据时被触发;
  2. delete触发器:从表中删除数据时被触发;
  3. update触发器:修改表中数据时被触发。

当遇到下列情形时,应考虑使用DML触发器:

  1. 经过数据库中的相关表实现级联更改
  2. 防止恶意或者错误的insert、update和delete操做,并强制执行check约束定义的限制更为复杂的其余限制。
  3. 评估数据修改先后表的状态,并根据该差别才去措施。

2.DDL(数据定义语言,Data Definition Language)触发器

 DDL触发器是当服务器或者数据库中发生数据定义语言(主要是以create,drop,alter开头的语句)事件时被激活使用,使用DDL触发器能够防止对数据架构进行的某些更改或记录数据中的更改或事件操做。

3.登陆触发器

    登陆触发器将为响应 LOGIN 事件而激发存储过程。与 SQL Server 实例创建用户会话时将引起此事件。登陆触发器将在登陆的身份验证阶段完成以后且用户会话实际创建以前激发。所以,来自触发器内部且一般将到达用户的全部消息(例如错误消息和来自 PRINT 语句的消息)会传送到 SQL Server 错误日志。若是身份验证失败,将不激发登陆触发器。

四:触发器的工做原理

触发器触发时:

  1. 系统自动在内存中建立deleted表或inserted表;
  2. 只读,不容许修改,触发器执行完成后,自动删除。

inserted表:

  1. 临时保存了插入或更新后的记录行;
  2. 能够从inserted表中检查插入的数据是否知足业务需求;
  3. 若是不知足,则向用户发送报告错误消息,并回滚插入操做。 

deleted表:

  1. 临时保存了删除或更新前的记录行;
  2. 能够从deleted表中检查被删除的数据是否知足业务需求;
  3. 若是不知足,则向用户报告错误消息,并回滚插入操做。

inserted表和deleted表对照: 

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

 

 

 

五:建立触发器

 建立触发器的语法: 

复制代码
CREATE TRIGGER trigger_name
 ON table_name
 [WITH ENCRYPTION]
  FOR | AFTER | INSTEAD OF [DELETE, INSERT, UPDATE]
 AS 
  T-SQL语句
GO
--with encryption 表示加密触发器定义的sql文本
--delete,insert,update指定触发器的类型
复制代码

 准备测试数据:

复制代码
--建立学生表
create table student(
    stu_id int identity(1,1) primary key,
    stu_name varchar(10),
    stu_gender char(2),
    stu_age int
)
复制代码

1.建立insert触发器

复制代码
--建立insert触发器
create trigger trig_insert
on student
after insert
as
begin
    if object_id(N'student_sum',N'U') is null--判断student_sum表是否存在
        create table student_sum(stuCount int default(0));--建立存储学生人数的student_sum表
    declare @stuNumber int;
    select @stuNumber = count(*)from student;
    if not exists (select * from student_sum)--判断表中是否有记录
        insert into student_sum values(0);
    update student_sum set stuCount =@stuNumber; --把更新后总的学生数插入到student_sum表中
end
复制代码
复制代码
--测试触发器trig_insert-->功能是向student插入数据的同时级联插入到student_sum表中,更新stuCount
--由于是后触发器,因此先插入数据后,才触发触发器trig_insert;
insert into student(stu_name,stu_gender,stu_age)values('吕布','男',30);
select stuCount 学生总人数 from student_sum;    
insert into student(stu_name,stu_gender,stu_age)values('貂蝉','女',30);            
select stuCount 学生总人数 from student_sum;
insert into student(stu_name,stu_gender,stu_age)values('曹阿瞒','男',40);                
select stuCount 学生总人数 from student_sum;
复制代码

执行上面的语句后,结果以下图所示:

 既然定义了学生总数表student_sum表是向student表中插入数据后才计算学生总数的,因此学生总数表应该禁止用户向其中插入数据

复制代码
--建立insert_forbidden,禁止用户向student_sum表中插入数据
create trigger insert_forbidden
on student_sum
after insert
as
begin
    RAISERROR('禁止直接向该表中插入记录,操做被禁止',1,1)--raiserror 是用于抛出一个错误
rollback transaction
end 
复制代码
--触发触发器insert_forbidden
insert student_sum (stuCount) values(5);

结果以下:

 2.建立delete触发器

  用户执行delete操做,就会激活delete触发器,从而控制用户可以从数据库中删除数据记录,触发delete触发器后,用户删除的记录会被添加到deleted表中,原来表的相应记录被删除,因此在deleted表中查看删除的记录。

复制代码
--建立delete触发器
create trigger trig_delete
on student 
after delete
as
begin
    select stu_id as 已删除的学生编号,stu_name stu_gender,stu_age
    from deleted
end;
复制代码
--执行一一条delete语句触发trig_delete触发器
delete from student where stu_id=1;

结果以下:

 3.建立UPDATE触发器

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

复制代码
--建立update触发器
create trigger trig_update
on student
after update
as
begin
    declare @stuCount int;
    select @stuCount=count(*) from student;
    update student_sum set stuCount =@stuCount;
    select stu_id as 更新前学生编号,stu_name as 更新前学生姓名 from deleted
    select stu_id as 更新后学生编号,stu_name as 更新后学生姓名 from inserted
end
复制代码
--建立完成,执行一条update语句触发trig_update触发器
update student set stu_name='张飞' where stu_id=2;

 4.建立替代触发器

  与前面介绍的三种after触发器不一样,SqlServer服务器在执行after触发器的sql代码后,先创建临时的inserted表和deleted表,而后执行代码中对数据库操做,最后才激活触发器中的代码。而对于替代(instead of)触发器,SqlServer服务器在执行触发instead of 触发器的代码时,先创建临时的inserted表和deleted表,而后直接触发instead of触发器,而拒绝执行用户输入的DML操做语句。

复制代码
--建立instead of 触发器 
create trigger trig_insteadOf
on student 
instead of insert
as 
begin
    declare @stuAge int;
    select @stuAge=(select stu_age from inserted)
if(@stuAge >120)
    select '插入年龄错误' as '失败缘由'
end
复制代码

建立完成,执行一条insert语句触发触发器trig_insteadOf

5.嵌套触发器介绍

 若是一个触发器在执行操做时调用了另一个触发器,而这个触发器又接着调用了下一个触发器,那么就造成了嵌套触发器。嵌套触发器在安装时就被启用,可是可使用系统存储过程sp_configure禁用和从新启用嵌套触发器。

 

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

  • 默认状况下,嵌套触发器配置选项是开启的。
  • 在同一个触发器事务中,一个嵌套触发器不能被触发两次。
  • 因为触发器是一个事务,若是在一系列嵌套触发器的任意层次中发生错误,则整个事物都将取消,并且全部数据回滚。

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

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

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

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

6.递归触发器

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

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

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

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

咱们举例解释以下,假若有表一、表2名称分别为 T一、T2,在 T一、T2 上分别有触发器 G一、G2。

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

设置直接递归:

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

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

六:管理触发器 

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

2.禁用启用触发器

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

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

  若是把“触发器名称”换成“ALL”,则表示禁用或启用该表的所有触发器。

3修改触发器

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

4.删除触发器

 --语法格式:
      DROP  TRIGGER   { trigger } [ ,...n ]
参数:
 trigger: 要删除的触发器名称
 n:表示能够删除多个触发器的占位符       
相关文章
相关标签/搜索