SQL Server 中的回滚

全部回滚方法3,则只回滚错误操作语句(就是说这句不执行了,/,事务保证性对业务逻辑会有重要影响,事务处理是数据的重要特性,和触发器中事务个故事,如果你有对触发器和事务的概念

金沙国际唯一官网网址 20
USE [TestDB]
GO
/****** 对象:  Table [dbo].[Person]    脚本日期: 11/23/2008 13:37:48 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[Person](
    [PersonId] [nchar](18) NOT NULL,
    [PersonName] [nchar](20) NOT NULL,
 CONSTRAINT [PK_Person] PRIMARY KEY CLUSTERED 
(
    [PersonId] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
) ON [PRIMARY]

 

事务处理是数额的根本特点。越发是对此有个别支出系统,事务保险性对业务逻辑会有根本影响。golang的mysql驱动也卷入好了工作相关的操作。我们已经学习了db的Query和Exec方法处理查询和改动数据库。

引述

私下认可景况下若是履行一个事情中冒出谬误,则只回滚错误操作语句(便是说那句不举办了,算不上回滚),错误处在此以前或之后的不错操作语句照旧会被交付。如:

使用的表结构如下:

tx对象

貌似查询利用的是db对象的法子,事务则是采纳其余三个对象。sql.Tx对象。使用db的Begin方法能够创建tx对象。tx对象也有数据库交互的Query,Exec和Prepare方法。用法和db的有关用法类似。查询或涂改的操作甘休之后,必要调用tx对象的Commit提交大概Rollback方法回滚。

要是创设了tx对象,事务处理都凭借与tx对象,这么些目的会从连接池中取出多个悠然的接连,接下去的sql执行都依照这些一而再,直到commit恐怕rollback调用之后,才会把连接释放到连接池。

在事务处理的时候,不可能使用db的查询形式,纵然后者能够获取数据,不过这不属于同一个事务处理,将不会接受commit和rollback的更动,1个粗略的事务例子如下:

tx, err := db.Begin()tx.Exectx.Exectx.commit()

在tx中动用db是漏洞百出的:

tx, err := db.Begin()db.Exectx.Exectx.commit()

上述代码在调用db的Eexc方法的时候,tx会绑定连接到工作中,db则是相当的3个总是,两者不是同2个事情。要求留意,Begin和Commit方法,与sql语句中的BEGIN或COMMIT语句没有关联。


Use TestDB

Begin TransAction
    Insert Into Person(PersonId,PersonName)
                Values('1','Name1')
    Insert Into Person(PersonId,PersonName)
                Values('1','Name1')
    Insert Into Person(PersonId,PersonName)
                Values('3','Name3')
Commit TransAction
/*
    Select 一下 有'1','Name1'和'3','Name3',
    说明只有第二句的错误被取消了
*/

金沙国际唯一官网网址 1😉

业务与连接

始建Tx对象的时候,会从连接池中取出连接,然后调用相关的Exec方法的时候,连接依旧会绑定在改事务处理中。在实质上的事务处理中,go只怕成立不一致的连天,不过那多少个其余总是都不属于该业务。例如地方例子中db创建的连年和tx的连年就不是二次事。

作业的连年生命周期从Beigin函数调用起,直到Commit和Rollback函数的调用甘休。事务也提供了prepare语句的选拔方法,不过急需动用Tx.Stmt方法创设。prepare设计的初衷是屡屡实践,对于事情,有恐怕需求频繁进行同1个sql。不过无论平常的prepare和事务处理,prepare对于连日来的田管都有点小复杂。因而私以为尽量防止在工作中使用prepare形式。例如上面例子就便于造成错误:

tx, _ := db.Begin()defer tx.Rollback()stmt, _ tx.Prepare("INSERT ...")defer stmt.Close()tx.Commit()

因为stmt.Close使用defer语句,即函数退出的时候再清理stmt,可是实际执行进度的时候,tx.Commit就早已出狱了连年。当函数退出的时候,再实施stmt.Close的时候,连接或者有被应用了。

     首先,
说下自家写篇小说的指标,作者愿意能把自家对触发器的明亮,分享出来与你一块学学。尽管您有对触发器和工作的概念,有个别明白,那篇小说,对你的话会是很简单,或能让您更进一步的摸底触发器里面包车型地铁有的故事,和触发器中工作个旧事。在这边文章里面,小编不会从触发器和工作的定义去讲述,而是从普遍的二种触发器类型(DML触发器
& DDL触发器)和After触发器 &  Instead Of
触发器的行使不一样,起初说起它们,然后是说与事务有关的典故。假如,你有啥样建议和看法,都足以经过文章后边的还原与我交流,大概通过E-Mail情势,与
作者沟通;作者的Email地址是:glal@163.com

整整回滚的方法1:打开 XACT_ABORT

USE [TestDB]
GO
/****** 对象:  Table [dbo].[Person]   
脚本日期: 1百分之五十3/二〇〇八 13:37:48 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[Person](
    [PersonId] [nchar](18) NOT NULL,
    [PersonName]金沙国际唯一官网网址, [nchar](20) NOT NULL,
 CONSTRAINT [PK_Person] PRIMARY KEY CLUSTERED 
(
    [PersonId] ASC
)WITH (PAD_INDEX  = OFF,
STATISTICS_NORECOMPUTE  = OFF,
IGNORE_DUP_KEY = OFF,
ALLOW_ROW_LOCKS  = ON,
ALLOW_PAGE_LOCKS  = ON)
ON [PRIMARY]
) ON [PRIMARY]

事情并发

对于sql.Tx对象,因为工作进度唯有1个总是,事务内的操作都以各类执行的,在起来下1个数据库交互此前,必须先形成上二个数据库交互。例如上面包车型大巴例证:

rows, _ := db.Query("SELECT id FROM user") for rows.Next() { var mid, did int rows.Scan db.QueryRow("SELECT id FROM detail_user WHERE master = ?", mid).Scan }

调用了Query方法之后,在Next方法中取结果的时候,rows是保卫安全了七个老是,再度调用QueryRow的时候,db会再从连接池取出二个新的接连。rows和db的连接两者能够存活,并且相互不影响。

唯独,那样逻辑在事务处理司令员会失灵:

rows, _ := tx.Query("SELECT id FROM user")for rows.Next() { var mid, did int rows.Scan tx.QueryRow("SELECT id FROM detail_user WHERE master = ?", mid).Scan}

tx执行了Query方法后,连接转移到rows上,在Next方法中,tx.QueryRow将尝试得到该连接进行数据库操作。因为还向来不调用rows.Close,由此底层的总是属于busy状态,tx是无力回天再进行查询的。上边包车型大巴事例看起来有个别傻,究竟涉及那样的操作,使用query的join语句就能避开这么些难题。例子只是为了表达tx的选拔难题。

     在上边包车型地铁情节,用到有些SQL Server
触发器和事务的某个术语,假使有点不清楚的地点,能够查阅MSDN资料库,或SQL
Server本地支持文书档案:

Use TestDB
SET XACT_ABORT ON -- 打开
Begin TransAction
    Insert Into Person(PersonId,PersonName)
                Values('1','Name1')
    Insert Into Person(PersonId,PersonName)
                Values('1','Name1')
    Insert Into Person(PersonId,PersonName)
                Values('3','Name3')
Commit TransAction
/*
    当 SET XACT_ABORT 为 ON 时,
    如果执行 Transact-SQL 语句产生运行时错误,
    则整个事务将终止并回滚。 
    默认情况下它是OFF状态。
*/

金沙国际唯一官网网址 2😉

实践

前边对工作解释了一堆,说了那么多,其实还比不上share的code。下边就工作的利用做简单的牵线。因为事情是单个连接,由此任何事务处理进程的产出了丰盛,都供给动用rollback,一方面是为了保险数据完整一致性,另一方面是假释工作绑定的连接。

func doSomething(){ panic("A Panic Running Error")}func clearTransaction(tx *sql.Tx){ err := tx.Rollback() if err != sql.ErrTxDone && err != nil{ log.Fatalln }}func main() { db, err := sql.Open("mysql", "root:@tcp(127.0.0.1:3306)/test?parseTime=true") if err != nil { log.Fatalln } defer db.Close() tx, err := db.Begin() if err != nil { log.Fatalln } defer clearTransaction rs, err := tx.Exec("UPDATE user SET gold=50 WHERE real_name='vanyarpy'") if err != nil { log.Fatalln } rowAffected, err := rs.RowsAffected() if err != nil { log.Fatalln } fmt.Println(rowAffected) rs, err = tx.Exec("UPDATE user SET gold=150 WHERE real_name='noldorpy'") if err != nil { log.Fatalln } rowAffected, err = rs.RowsAffected() if err != nil { log.Fatalln } fmt.Println(rowAffected) doSomething() if err := tx.Commit(); err != nil { // tx.Rollback() 此时处理错误,会忽略doSomthing的异常 log.Fatalln }}

我们定义了1个clearTransaction函数,该函数会执行rollback操作。因为大家事务处理进程中,任何一个错误都会导致main函数退出,由此在main函数退出执行defer的rollback操作,回滚事务和刑满释放解除劳教连接。

若是不添加defer,只在终极Commit后check错误err后再rollback,那么当doSomething发生十分的时候,函数就退出了,此时还并未履行到tx.Commit。这样就导致工作的连天没有关闭,事务也尚无回滚。

  • DML触发器(DML Triggers)
  • DDL触发器(DDL Triggers)
  • 作业格局(Transaction modes)
  • 显式事务(Explicit Transactions)
  • 活动提交业务(Autocommit Transactions)
  • 隐式事务(Implicit Transactions)
  • 批范围的政工(Batch-scoped Transactions)

万事回滚方法2:使用Try…Catch

 

总结

database/sql提供了事务处理的功能。通过Tx对象实现。db.Begin会创制tx对象,后者的Exec和Query执行工作的数据库操作,最终在tx的Commit和Rollback中做到数据库事务的交付和回滚,同时释放连接。

tx事务环境中,唯有一个数据库连接,事务内的Eexc都以各种执行的,事务中也能够使用db举办查询,但是db查询的长河会新建连接,这几个一连的操作不属于该事务。

关于database/sql和mysql的驱动,大家早就分三部分内容介绍了。下一节,将会对前边的内容举行梳理总括,包罗错误处理和注意事项的补偿。

After触发器 Vs Instead Of触发器

            After 触发器将在处理触发操作(Insert、Update 或
Delete)、Instead Of 触发器和平条约束之后激发。Instead
Of是将在拍卖约束前激发,以代表触发操作。下边两张图描述了After触发器和Instead
Of触发器的实施先后顺序。

    
金沙国际唯一官网网址 3      
金沙国际唯一官网网址 4 

    
图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语句后的事态。

金沙国际唯一官网网址 5

本例子,只看到引发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

金沙国际唯一官网网址 6  

此间,看到,先是触发器操作,再是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

金沙国际唯一官网网址 7金沙国际唯一官网网址 8

能够见到,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的操作顺序:

    
金沙国际唯一官网网址 9

     图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

重返错误音信,

金沙国际唯一官网网址 10

行使上面相同的法门,大家证实DDL触发器中,不会创设Deleted表;是还是不是创设Deleted
&
Inserted,也足以认为是DDL触发器与DML触发器分歧之处。在DLL触发器与DML触发器分化的三个第叁特点是功能域,DML触发器只好使用在数量库层(Database
Level)的表和视图上,而DDL触发器应用于数据库层(Database
Level)和服务器层(Server
Level);DDL触发器的功用域取决于事件。下边简单描述下事件组的始末。

 

数量库层事件首要包含:

  1. DDL Table events: Create table, Alter table, Drop table
  2. DDL view events : Create view, Alter view, Drop view
  3. DDL trigger events :Create trigger, Drop trigger, Alter trigger
  4. DDL synonym events: Create synonym, drop synonym
  5. DDL Index events: Create index, Alter index, Drop Index
  6. 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
  7. 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

劳务器层事件非同小可涵盖:

  1. Create Database, Drop Database
  2. Create Login, Drop Login, Alter Login

 

 

触发器和作业的旧事


      在如今的多少个例子中,如DML触发器例子,Insert
语句执行后,因为触发器操作 或
Check处理错误,没有把多少真正的插入到表Contact中。其实,当执行触发器时,触发器的操作看似有一个未成功的事务在起效用。
通过多少个例子来上课触发器和作业的故事。

创设2个表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

Insert Into ContactHIST(ContactID,Name,Sex)

    Select ID,Name,Sex From deleted 

 

Rollback Tran 

 

Begin Tran

Go

测试数据,

use tempdb

Go

Insert Into Contact (Name,Sex) Values ('Bill','F')

Go

--Update

Update Contact 

    Set Sex='M'

    Where Name='Bill'

Go

Select * From Contact

Select * From ContactHIST

Go

测试结果:

金沙国际唯一官网网址 11金沙国际唯一官网网址 12

从上面的测试情状,看出,Update
Contact触发tr_Contact触发器操作,触发器里面包车型地铁Rollback Tran
动作导致了触发器外面包车型客车Update语句执行回滚,而Rollback Tran
语句前面的Begin
Tran语句,重假使应用于保持整个工作的完整性。为了更能清楚这一历程,小编模拟了二个触发器中的事务先导终结进度。

金沙国际唯一官网网址 13

图4.

在SQL Server 2006 和 SQL Server
2010上面,能够看到如图4.的功用。在低版本的SQL
Server上,也许会产出谬误提醒意况,不管什么样,在触发器外面,SQL
Server都会Rollback Tran。上边笔者做个谬误提醒的例证。

修改触发器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

Insert Into ContactHIST(ContactID,Name,Sex)

    Select ID,Name,Sex From deleted 

 

Rollback Tran 

 

--Begin Tran 

Go

重复履行Update操作,

use tempdb

Go

Update Contact 

    Set Sex='M'

    Where Name='Bill'

Go    

Select @@TRANCOUNT    

Go

Select * From Contact

Select * From ContactHIST

Go

金沙国际唯一官网网址 14金沙国际唯一官网网址 15

在触发器里面没有Begin
Tran语句动作,触发器外面也能回滚操作。那里我们能够透过查询表数据和@@Trancount来判断。

         其实,上边的事例,Update语句,是以活动提交业务(Autocommit
Transactions)方式 伊始执行的,触发器里Rollback Tran前面,不管有没有Begin
Tran ,最终都会工作都会交回给SQL
Server自动提交事务管理。当然,在DML触发器中,你能够利用显式事务(Explicit
Transactions),或打开隐式事务(Implicit Transactions)
来支配,当然你也得以运用于批范围的作业(Batch-scoped Transactions)
中。那里,笔者透过开启隐式事务(Implicit Transactions)
的事例来说,触发器与业务的涉嫌。

修改触发器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

Print N'触发器里Insert 前,@@Trancount='+Rtrim(@@Trancount)

 

Insert Into ContactHIST(ContactID,Name,Sex)

    Select ID,Name,Sex From deleted 

 

Print N'触发器里Insert后,Rollback Tran 前,@@Trancount='+Rtrim(@@Trancount)

 

Rollback Tran 

 

Print N'触发器里Rollback Tran 后,@@Trancount='+Rtrim(@@Trancount)

 

Begin Tran 

Go

拉开隐式事务(Implicit Transactions) 来测试,

use tempdb

Go

Set Implicit_transactions On /**/

Go

Print N'Update Contact前,@@Trancount='+Rtrim(@@Trancount)

 

Update Contact 

    Set Sex='M'

    Where Name='Bill'



Print N'Update Contact后,@@Trancount='+Rtrim(@@Trancount)

 

Rollback Tran

 

Print N'触发器外面Rollback Tran 后,@@Trancount='+Rtrim(@@Trancount)



Go    

Set Implicit_transactions Off /**/

Go

 

Go

Select * From Contact

Select * From ContactHIST

Go

 

金沙国际唯一官网网址 16

 

此地,你是还是不是察觉2个很有趣的题材,在触发器理,执行Insert
ContactHIST在此以前,@@Trancount=1,执行Insert后,@@Trancount依然为1,触发器外面Update
Contact后,@@Trancount就成为了2,。那里能够清楚成,你在触发器里面,发出两个Begin
Tran,那么SQL Server 就会创制二个嵌套事务。当您在触发器里面,在Rollback
Tran后边屏蔽掉Begin Tran,就会出现错误3609,如,

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

Print N'触发器里Insert 前,@@Trancount='+Rtrim(@@Trancount)

 

Insert Into ContactHIST(ContactID,Name,Sex)

    Select ID,Name,Sex From deleted 

 

Print N'触发器里Insert后,Rollback Tran 前,@@Trancount='+Rtrim(@@Trancount)

 

Rollback Tran 

 

Print N'触发器里Rollback Tran 后,@@Trancount='+Rtrim(@@Trancount)

 

Go

 

金沙国际唯一官网网址 17

那里,能够观望事情在触发器中Rollback,又不曾拉开新的作业,导致整个批处理就暂停,不会继续执行触发器外面包车型地铁Rollback
Tran操作。倘使,你在触发器中利用Begin Tran …… Commit
Tran格式,那么触发器Commit
Tran不会潜移默化到外围的事情;下边描述两种普遍触发器辽宁中华工程集团作的景色:

金沙国际唯一官网网址 18金沙国际唯一官网网址 19金沙国际唯一官网网址 20

图5.                                                                            
图6.                                                                          
图7.

图5.叙述在触发器中包蕴Begin Tran …… Commit Tran的情况,

图6.叙述在触发器中蕴藏Save Tran savepoint_name …… Rollback Tran
savepoint_name 的境况,触发器中的Rollback Tran
只会回滚钦赐的保存点,不会影响到触发器外面包车型客车Commit Tran Or Rollback
Tran操作。

图7.描述在触发器中蕴藏Rollback Tran的图景,不管触发器里面有没有Begin
Tran,都会出现错误3609,中止批处理。

   
注:DDL触发器操作能够触发器中回滚操作,能够采取命令如Rollback,但严重错误恐怕会导致整个工作自动回滚。无法回滚发生在
DDL 触发器正文内的 Alter Database事件。在触发器中动用Rollback … Begin
Tran
恐怕会造成意外的结果,在并未确认和测试情状下,请不要随便在触发器中一向动用Rollback
…Begin Tran处理方式.尤其是Create Database事件,在SQL Server 二〇〇九和SQL
Server 二零零五环境下,产生的结果区别。

Rollback …Begin Tran情况:

Create Trigger ….

As

……

Rollback

Begin Tran

End

小结


 

     回看前文至后文,从After触发器VsInstead Of 触发器,说到DML触发器 Vs
DDL触发器,再到触发器广西中华工程企业作的典故。恐怕有点地点描述的有点模糊,有个别地点只有一笔带过;你在测试代码进度中,大概发现有点地点与这里测试的图景例外,这也许是因为SQL
Server版本的区别,导致部分测试结果差异。无论怎么着,只要您感觉对你询问触发器,有些拉扯,就OK了。

     

Use TestDB
Begin Try
    Begin TransAction
        Insert Into Person(PersonId,PersonName)
                    Values('1','Name1')
        Insert Into Person(PersonId,PersonName)
                    Values('1','Name1')
        Insert Into Person(PersonId,PersonName)
                    Values('3','Name3')
    Commit TransAction
End Try
Begin Catch
    Rollback TransAction
End Catch
/*
    使用TryCatch来捕获异常。
    如果 TRY 块内生成的错误导致当前事务的状态失效,
    则将该事务归类为不可提交的事务。
    如果通常在 TRY 块外中止事务的错误在 TRY 内发生时,
    就会导致事务进入不可提交状态。
    不可提交的事务只能执行读操作或 ROLLBACK TRANSACTION。
    该事务不能执行任何可能生成写操作或 COMMIT TRANSACTION 的 Transact-SQL 语句。
    如果事务被分类为不可提交的事务,则 XACT_STATE 函数会返回值 -1。
*/

 

全体回滚方法3:自定义错误变量

暗中认可情形下借使推行贰个作业中冒出谬误,则只回滚错误操作语句(就是说那句不进行了,算不上回滚),错误处从前或之后的没错操作语句依然会被交付。如: