触发器(trigger)是SQL server 提供给程序员和数据分析员来保证数据完整性的一种方法,它是与表事件相关的特殊的存储过程,它的执行不是由程序调用,也不是手工启动,而是由事件来触发,比如当对一个表进行操作( insert,delete, update)时就会激活它执行。触发器经常用于加强数据的完整性约束和业务规则等。
1. DML(数据操作语言,Data Manipulation Language)触发器
DML触发器是一些附加在特定表或视图上的操作代码,当数据库服务器中发生数据操作语言事件时执行这些操作。SqlServer中的DML触发器有三种:
insert触发器:向表中插入数据时被触发;
update触发器:修改表中数据时被触发;
delete触发器:从表中删除数据时被触发。
当遇到下列情形时,应考虑使用DML触发器:
通过数据库中的相关表实现级联更改
防止恶意或者错误的insert、update和delete操作,并强制执行check约束定义的限制更为复杂的其他限制。
评估数据修改前后表的状态,并根据该差异才去措施。
2. DDL(数据定义语言,Data Definition Language)触发器
DDL触发器是当服务器或者数据库中发生数据定义语言(主要是以create,drop,alter开头的语句)事件时被激活使用,使用DDL触发器可以防止对数据架构进行的某些更改或记录数据中的更改或事件操作。
3. 登录触发器
登录触发器将为响应 LOGIN 事件而激发存储过程。与 SQL Server 实例建立用户会话时将引发此事件。登录触发器将在登录的身份验证阶段完成之后且用户会话实际建立之前激发。因此,来自触发器内部且通常将到达用户的所有消息(例如错误消息和来自 PRINT 语句的消息)会传送到 SQL Server 错误日志。如果身份验证失败,将不激发登录触发器。
其中 DML 触发器比较常用,根据 DML 触发器触发的方式不同又分为以下两种情况:
after 触发器(之后触发):其中 after 触发器要求只有执行 insert、update、delete 某一操作之后触发器才会被触发,且只能定义在表上。
instead of 触发器 (之前触发):instead of 触发器并不执行其定义的操作(insert、update、delete)而仅是执行触发器本身。可以在表或视图上定义 instead of 触发器。
DML 触发器有两个特殊的表:插入表(instered)和删除表(deleted),这两张表是逻辑表。这两个表是建立在数据库服务器的内存中,而且两张表的都是只读的。这两张表的结构和触发器所在的数据表的结构是一样的。当触发器完成工作后,这两张表就会被删除。Inserted 表的数据是插入或是修改后的数据,而 deleted 表的数据是更新前的或是已删除的数据。
DML触
Insert触发器,使用到inserted表;
Update触发器,使用到deleted表和inserted表;
Delete触发器,使用到deleted表。
下面引用一张图,简单明了展示了DML触发器:
–标准语法
Create TRIGGER 触发器名
ON 表名
AFTER insert/update/delete
AS
BEGIN
SET NOCOUNT ON;
Declare @变量 数据类型,.....
Select @变量=字段 from 表名
处理内容
END
Update 触发器:
在向目标表中更新数据后,会触发该表的Update 触发器,系统自动在内存中创建deleted表和inserted表,deleted表存放的是更新前的数据,inserted表存放的是更新的数据。
Delete 触发器:
在向目标表中删除数据后,会触发该表的Delete 触发器,系统自动在内存中创建deleted表,deleted表存放的是删除的数据。
DDL触发器分为:
Transact-SQL DDL触发器:一种特殊类型的Transact-SQL存储过程,用于响应服务器范围或数据库范围的事件而执行一个或多个Transact-SQL语句,极大多数触发器都是此类
CLR DDL触发器:执行一个或多个用托管代码编写的方法,这些方法是在.NET Framework中创建并在SQL Server中上载的程序集的成员
--标准语法
CREATE [ OR ALTER ] TRIGGER trigger_name
ON { ALL SERVER | DATABASE } --触发器应用范围为当前数据库|服务器
[ WITH <ddl_trigger_option> [ ,...n ] ]
{ FOR | AFTER } --指定仅在触发SQL语句中指定的所有操作成功启动后才触发触发器
{ event_type | event_group } [ ,...n ]
AS { sql_statement [ ; ] [ ,...n ] | EXTERNAL NAME < method specifier > [ ; ] } --触发条件和操作,在尝试操作时,在Transact-SQL语句中指定的触发操作将生效。
<ddl_trigger_option> ::=
[ ENCRYPTION ] --遮盖CREATE TRIGGER语句的文本,防止触发器作为SQL Server复制的一部分发布
[ EXECUTE AS Clause ] --指定执行触发器的安全上下文,该选项能够控制SQL Server实例来验证触发器所引用的任何数据库对象的权限的用户帐户。
{event_type|event_group} --启动后导致DDL触发器触发的Transact-SQL语言事件的名称|Transact-SQL语言事件的预定义分组的名称
DDL触发器权限
创建具有服务器作用域(ON ALL SERVER)DDL触发器,需要对服务器具有CONTROL SERVER权限。
创建具有数据库范围(ON DATABASE)的DDL触发器,需要在当前数据库中具有ALTER ANY DATABASE DDL TRIGGER权限
对于任何数据库中的数据库成功连接,我们使用两个术语。
如果任何用户无法通过SQL Server进行身份验证(使用错误的凭据),则SQL Server不会执行登录触发器。 SQL Server在登录触发器触发之前启动隐式事务。 它独立于任何用户事务。 对于登录触发器,事务计数为1。如果SQL返回异常,则其值设置为零。 它使隐式事务失败,并且未建立用户会话。 如果错误在触发器内部的严重性大于20,则用户连接也会失败。
使用SQL Server中的登录触发器限制SQL Server连接的总数
有时,我们需要限制SQL Server连接的总数。 太多的连接可能会导致性能问题,因此我们可以使用登录触发器来解决此目的。 默认情况下,SQL Server允许无限数量的并发连接到SQL Server。 您可以在SQL Server属性中进行验证。
我们可以使用DMV sys.dm_exec_connections来区分系统和用户进程。 在下面的查询中,我们创建一个登录触发器,以允许最多三个连接。 可以看到,我们在登录触发器中使用了FOR LOGON子句。
1 CREATE [ OR ALTER ] TRIGGER trigger_name
2 ON ALL SERVER
3 [ WITH <logon_trigger_option> [ ,...n ] ]
4 { FOR| AFTER } LOGON
5 AS { sql_statement [ ; ] [ ,...n ] | EXTERNAL NAME < method specifier > [ ; ] }
6
7 <logon_trigger_option> ::=
8 [ ENCRYPTION ]
9 [ EXECUTE AS Clause ]
参数:
CREATE OR ALTER:
创建或者有条件的修改触发器(即要修改的触发器必须已经存在)。
DATABASE:
将 DDL 触发器的范围应用于当前数据库。如果指定,触发器会在当前数据库中发生 event_type 或 event_group 时触发。
ALL SERVER:
将 DDL 或登录触发器的作用域应用于当前服务器。如果指定,触发器会在当前服务器的任何地方发生 event_type 或 event_group 时触发。
WITH ENCRYPTION:
加密 CREATE TRIGGER 语句的文本。使用 WITH ENCRYPTION 可以防止触发器作为 SQL Server 复制的一部分进行发布。无法为 CLR 触发器指定 WITH ENCRYPTION。
EXECUTE AS:
指定执行触发器的安全上下文。以便能够控制 SQL Server 实例用于验证触发器引用的任何数据库对象的权限的用户帐户。
NATIVE_COMPILATION:
表示触发器是本地编译的。
SCHEMABINDING:
指定触发器引用的表不能被删除或更改。
FOR | AFTER:
AFTER 指定仅在触发 SQL 语句中指定的所有操作成功执行时触发 DML 触发器。所有引用级联操作和约束检查在此触发器触发之前也必须成功。当 FOR 是指定的唯一关键字时,AFTER 是默认值。视图无法定义AFTER触发器。
INSTEAD OF:
指定执行 DML 触发器而不是触发 SQL 语句,因此覆盖触发语句的操作。无法为 DDL 或登录触发器指定 INSTEAD OF。
对于 INSTEAD OF 触发器,在具有指定级联动作 ON DELETE 的引用关系的表上不允许使用 DELETE 选项。类似地,在具有指定级联动作 ON UPDATE 的引用关系的表上,不允许 UPDATE 选项。
{[DELETE] [,] [INSERT] [,] [UPDATE]} :
指定在针对此表或视图进行尝试时激活 DML 触发器的数据修改语句。必须至少指定一个选项。在触发器定义中允许以任何顺序对这些选项进行任意组合。
event_type:
是执行后导致 DDL 触发器触发的 Transact-SQL 语言事件的名称。
event_group:
是 Transact-SQL 语言事件的预定义分组的名称。属于任何 Transact-SQL 语言事件执行后的 DDL 触发器触发 event_group。
sql_statement:
是触发条件和动作。触发条件指定附加条件,以确定尝试的 DML,DDL 或登录事件是否导致执行触发器操作。
对于 CLR 触发器,指定要与触发器绑定的程序集的方法。该方法不得不引用任何参数并返回 void。class_name 必须是有效的 SQL Server 标识符,并且必须作为具有程序集可见性的程序集中的类存在。
触发器优点:
1.强化约束:强制复杂业务的规则和要求,能实现比check语句更为复杂的约束。
2.跟踪变化:触发器可以侦测数据库内的操作,从而禁止数据库中未经许可的更新和变化。
3.级联运行:侦测数据库内的操作时,可自动地级联影响整个数据库的各项内容。
4.嵌套调用:触发器可以调用一个或多个存储过程。触发器最多可以嵌套32层。
触发器缺点:
1. 可移植性差。
2.占用服务器资源,给服务器造成压力。
3.执行速度主要取决于数据库服务器的性能与触发器代码的复杂程度。
4.嵌套调用一旦出现问题,排错困难,而且数据容易造成不一致,后期维护不方便。
触发器使用建议:
1.尽量避免在触发器中执行耗时操作,因为触发器会与SQL语句认为在同一事务中,事务不结束,就无法释放锁。
2.避免在触发器中做复杂操作,影响触发器性能的因素比较多(Eg:产品版本,所使用的架构等),要想编写高效的触发器考虑因素比较多,编写高性能触发器还是很难的。
3.触发器编写时注意多行触发时的处理。(一般不建议使用游标)