SQL Server触发器及触发器中的事务学习

所属分类: 数据库 / MsSql 阅读数: 535
收藏 0 赞 0 分享
如果你有对触发器和事务的概念,有些了解,这篇文章,对你来说会是很简单,或能让你更进一步的了解触发器里面的一些故事,和触发器中事务个故事。在这边文章里面,我不会从触发器和事务的概念去讲述,而是从常见的两种触发器类型(DML触发器 & DDL触发器)和After触发器 &  Instead Of 触发器的应用不同,开始说起它们,然后是说与事务有关的故事。如果,你有什么建议和意见,都可以通过文章后面的回复与我沟通,或者通过E-Mail方式,与 我交流;我的Email地址是:glal@163.com

     在下面的内容,用到一些SQL Server 触发器和事务的一些术语,如果有些不明白的地方,可以查阅MSDN资料库,或SQL Server本地帮助文档:

DML触发器(DML Triggers) DDL触发器(DDL Triggers) 事务模式(Transaction modes) 显式事务(Explicit Transactions) 自动提交事务(Autocommit Transactions) 隐式事务(Implicit Transactions) 批范围的事务(Batch-scoped Transactions)

After触发器 Vs Instead Of触发器

            After 触发器将在处理触发操作(Insert、Update 或 Delete)、Instead Of 触发器和约束之后激发。Instead Of是将在处理约束前激发,以替代触发操作。下面两张图描述了After触发器和Instead Of触发器的执行先后顺序。

     image      
image 

     图1                                                                             图2

     左边的图1,描述了After触发器执行顺序情况,我在这里通过一个简单的例子来说明After触发器的执行顺序,以便能加深对左图1 After触发器的理解。

先创建表Contact

use tempdb
Go
if object_id('Contact') Is Not null 
 Drop Table Contact
Go
Create Table Contact
(
 ID int Primary Key Identity(1,1),
 Name nvarchar(50),
 Sex nchar(2) Check(Sex In(N'F',N'M')) Default('M')
)
Go

再创建After触发器tr_Contact

use tempdb
Go
If Exists(Select 1 From sys.triggers Where name='tr_Contact')
 Drop Trigger tr_Contact 
Go
Create Trigger tr_Contact On Contact After Insert
As
Select Name,Sex From Inserted /*显示Inserted表的内容,用来判断触发器执行的先后顺序*/
Go

然后Insert数据,判断After触发器的执行顺序

use tempdb
Go
Insert Into Contact (Name,Sex) Values ('Bill','U')
Go

这里,在没有运行Insert语句之前,我们可以判断,执行Insert过程会触发Check错误,因为字段Sex的值必须是”F” Or “M”,而这里将要插入的是”U”.好了,再来看运行Insert语句后的情况。

image

本例子,只看到引发Check约束冲突的错误,而无法看到Inserted表的数据,说明一点就是,引起Check约束之前,不会引发After触发器tr_Contact的操作。这就验证了图1的After触发器执行顺序情况。

     好了,接下来,我们再测试Instead Of触发器 图2的情况;我使用上边建好的测试表Contact来举例。

先修改触发器tr_Contact内容,

use tempdb
Go
If Exists(Select 1 From sys.triggers Where name='tr_Contact')
 Drop Trigger tr_Contact 
Go
Create Trigger tr_Contact On Contact Instead Of Insert
As
print '触发器作代替执行操作'
Insert Into Contact (Name,Sex) Select Name,Sex From Inserted /*代替触发器外面的Insert行为*/
Go

再Insert数据,观察SQL Server执行后的提示信息,

use tempdb
Go
Insert Into Contact (Name,Sex) Values ('Bill','U')
Go

image  

这里,看到,先是触发器操作,再是Check约束处理。本例中,在触发器里面使用一条Insert的语句来描述触发器的代替执行操作,这SQL语句通过Select表Inserted得到触发器外面Insert内容。当SQL Server执行到触发器里面的Insert语句,才会引起Check约束处理.倘若,在触发器tr_Contact没有Insert的代替行为,那么就不会出现Check约束处理错误的信息(注:没有Check错误信息,并不表示没有作Check处理)。修改上边的触发器tr_Contact内容,做个简易的验证.

use tempdb
Go
If Exists(Select 1 From sys.triggers Where name='tr_Contact')
 Drop Trigger tr_Contact 
Go
Create Trigger tr_Contact On Contact Instead Of Insert
As
print '触发器作代替执行操作'
Go
use tempdb
Go
Insert Into Contact (Name,Sex) Values ('Bill','U')
Go
Select * From Contact

imageimage

可以看到,Instead Of 触发器tr_Contact内容没有Insert的SQL语句,不会引发Check处理错误,而且检查Insert动作后的结果,发现表Contact也没有之前我们Insert的数据。这些足够验证了Instead Of触发器的执行先后顺序和代替执行操作。

 

 

 

DML 触发器 Vs DDL 触发器


      DML 触发器在 Insert、Update 和 Delete 语句上操作,可以作为After 触发器 和 Instead Of 触发器。

     DDL 触发器对 Create、Alter、Drop 和其他 DDL 语句以及执行 DDL 式操作的存储过程执行操作,只可作为After触发器,不能Instead Of触发器。

     前面的内容,有描述DML触发器中的After & Instead Of触发器内容,下面直接来看DDL的操作顺序:

     image

     图3.

     从图3.可以知道,在DDL触发器中,是没有创建Inserted & Deleted过程的,我们通过简单的例子去测试下。

     创建一个服务器范围内的DDL触发器,检查有没有Inserted 表,

use master
Go
If Exists(Select 1 From sys.server_triggers Where name='tr_createDataBase')
 Drop Trigger tr_createDataBase On All Server
Go
Create Trigger tr_createDataBase On All Server After Create_DataBase
As 
Select * From inserted
Go

执行创建数据库SQL语句,

use master
Go
Create Database myDataBase On Primary
(Name='MyDataBase_Data',Filename='E:\DATA\SQL2008DE01\MyDataBase_Data.mdf') Log On 
(Name='MyDataBase_Log',Filename='E:\DATA\SQL2008DE01\MyDataBase_Log.ldf')
Go

返回错误信息,

image

使用上边相同的方法,我们验证DDL触发器中,不会创建Deleted表;是否创建Deleted & Inserted,也可以认为是DDL触发器与DML触发器不同之处。在DLL触发器与DML触发器不同的一个重要特征是作用域,DML触发器只能应用在数据库层(Database Level)的表和视图上,而DDL触发器应用于数据库层(Database Level)和服务器层(Server Level);DDL触发器的作用域取决于事件。下面简单描述下事件组的内容。

 

数据库层事件主要包含:

    DDL Table events: Create table, Alter table, Drop table DDL view events : Create view, Alter view, Drop view DDL trigger events :Create trigger, Drop trigger, Alter trigger DDL synonym events: Create synonym, drop synonym DDL Index events: Create index, Alter index, Drop Index DDL Database level security events: Create User, Drop user, Alter user Create role, Drop role, Alter role Create application role, Drop application role, Alter Application role Create Schema, Drop Schema, Alter Schema Grant database access, Revoke database access, Deny Database access DDL Service broker events: Create Message type, Alter Message type, Drop Message type Create contract, Drop contract, Alter contract Create Service, Alter service, Drop Service Create route, Drop route, Alter route

服务器层事件主要包含:

    Create Database, Drop Database Create Login, Drop Login, Alter Login

 

 

触发器和事务的故事


      在前面的几个例子中,如DML触发器例子,Insert 语句执行后,因为触发器操作 或 Check处理错误,没有把数据真正的插入到表Contact中。其实,当执行触发器时,触发器的操作好像有一个未完成的事务在起作用。 通过几个例子来讲解触发器和事务的故事。

创建一个表ContactHIST,用于对表Contact作Update Or Delete操作时,把操作前的数据Insert到表ContactHIST中。

use tempdb
Go
if object_id('ContactHIST') Is Not null 
 Drop Table ContactHIST
Go
Create Table ContactHIST
(
 ID int Primary Key Identity(1,1),
 ContactID int,
 Name nvarchar(50),
 Sex nchar(2),
 ActionType nvarchar(10) Check(ActionType In('Update','Delete')),
 LastUpdateDate datetime Default(getdate())
)
Go

修改触发器tr_Contact内容,

use tempdb
Go
If Exists(Select 1 From sys.triggers Where name='tr_Contact')
 Drop Trigger tr_Contact 
Go
Create Trigger tr_Contact On Contact After Update,Delete
As
                
更多精彩内容其他人还在看

sqlserver中将varchar类型转换为int型再进行排序的方法

sql中把varchar类型转换为int型然后进行排序,如果我们数据库的ID设置为varchar型的 在查询的时候order by id的话
收藏 0 赞 0 分享

在SQL Server中使用SQL语句查询一个存储过程被其它所有的存储过程引用的存储过程名

在项目开发中如果有时修改了一个存储过程,但是如何能够快速的查找到使用了这个存储过程的其它存储过程呢
收藏 0 赞 0 分享

sqlserver bcp(数据导入导出工具)一般用法与命令详解

bcp是SQL Server中负责导入导出数据的一个命令行工具,它是基于DB-Library的,并且能以并行的方式高效地导入导出大批量的数据
收藏 0 赞 0 分享

重命名SQLServer数据库的方法

本文讲解重命名SQLServer 数据库,包括物理文件名、逻辑文件名的改名
收藏 0 赞 0 分享

SQL Server中通过reverse取某个最后一次出现的符号后面的内容(字符串反转)

昨天在项目中遇到了一个非常简单的问题,需要把SQL Server数据库中保存的一段路径地址取出其文件名,但SQL Server又没有现成的方法,最后在网上找到这样的一个方法,原理是先将字符串反转,取出第一个/的位置,从头进行截取后再次反转
收藏 0 赞 0 分享

使用SqlBulkCopy时应注意Sqlserver表中使用缺省值的列

今天,想将以前做的一个程序增加点功能,原本就使用SqlBulkCopy批量、定时的从目录中的txt文件导入数据到Sqlserver中。以前一直都使用正常,但是不知怎的就老是出现一个错误
收藏 0 赞 0 分享

Sqlserver 2000/2005/2008 的收缩日志方法和清理日志方法

讲解一下sql 2005日志怎么清理。一般情况下,SQL数据库的收缩并不能很大程度上减小数据库大小,其主要作用是收缩日志大小,应当定期进行此操作以免数据库日志过大
收藏 0 赞 0 分享

SQL Server 2000 清理日志精品图文教程

SQL Server 2000 数据库日志太大!如何清理SQL Server 2000的日志呢
收藏 0 赞 0 分享

SQL行号排序和分页(SQL查询中插入行号 自定义分页的另类实现)

如何在SQL中对行进行动态编号,加行号这个问题,在数据库查询中,是经典的问题
收藏 0 赞 0 分享

sql分类汇总及Select的自增长脚本

对错误信息进行分类汇总,并实现错误数据的自增长编号
收藏 0 赞 0 分享
查看更多