Golang Mysql笔记(四)--- 事务

2019-03-23 11:06栏目:程序人生

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方法处理查询和改动数据库。

引述

默许情状下一旦进行1个事务中冒出谬误,则只回滚错误操作语句(便是说那句不实施了,算不上回滚),错误处在此以前或之后的正确操作语句仍然会被提交。如:

接纳的表结构如下:

tx对象

相似查询利用的是db对象的章程,事务则是利用此外1个对象。sql.Tx对象。使用db的Begin方法能够创设tx对象。tx对象也有数据库交互的Query,Exec和Prepare方法。用法和db的相关用法类似。查询或改动的操作截止之后,需求调用tx对象的Commit提交可能Rollback方法回滚。

一旦创建了tx对象,事务处理都凭借与tx对象,这么些指标会从连接池中取出三个悠然的接连,接下去的sql执行都依据这几个一连,直到commit可能rollback调用之后,才会把连接释放到连接池。

在事务处理的时候,不能够使用db的询问情势,就算后者能够获取数据,但是那不属于同二个事务处理,将不会接受commit和rollback的变动,2个不难易行的事务例子如下:

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

在tx中动用db是不对的:

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

上述代码在调用db的Eexc方法的时候,tx会绑定连接到业务中,db则是额外的贰个总是,两者不是同一个政工。供给留意,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',
    说明只有第二句的错误被取消了
*/

ca888会员登录 1;)

事务与连接

开创Tx对象的时候,会从连接池中取出连接,然后调用相关的Exec方法的时候,连接照旧会绑定在改事务处理中。在事实上的事务处理中,go恐怕创设差异的连年,可是这几个别的连接都不属于该事情。例如地点例子中db创建的总是和tx的接连就不是二遍事。

事务的接连生命周期从Beigin函数调用起,直到Commit和Rollback函数的调用甘休。事务也提供了prepare语句的运用方式,可是急需使用Tx.Stmt方法成立。prepare设计的初衷是频仍推行,对于事情,有只怕须要频仍履行同多个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]    脚本日期: 13/63/2010 13:37:48 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[Person](
    [PersonId]ca888会员登录, [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对象,因为事情进度唯有八个再而三,事务内的操作都以逐一执行的,在上马下一个数据库交互从前,必须先成功上一个数据库交互。例如上面包车型大巴例证:

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会再从连接池取出3个新的连日。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状态。
*/

ca888会员登录 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 }}

小编们定义了贰个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触发器的执行先后顺序。

     ca888会员登录 3       ca888会员登录 4 

     图1                                                                             图2

     左侧的图1,描述了After触发器执行顺序意况,小编在那里经过3个简约的例证来表达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语句后的地方。

ca888会员登录 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

ca888会员登录 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

ca888会员登录 7ca888会员登录 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的操作顺序:

     ca888会员登录 9

     图3.

     从图3.足以知晓,在DDL触发器中,是平素不创立Inserted & Deleted进程的,大家因而简单的例子去测试下。

     创设1个服务器范围内的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:DATASQL2008DE01MyDataBase_Data.mdf') Log On 

(Name='MyDataBase_Log',Filename='E:DATASQL2008DE01MyDataBase_Log.ldf')

Go

归来错误音讯,

ca888会员登录 10

运用上边相同的措施,大家作证DDL触发器中,不会创设Deleted表;是不是制造Deleted & Inserted,也得以认为是DDL触发器与DML触发器差异之处。在DLL触发器与DML触发器分化的3个器重特色是功能域,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中。其实,当执行触发器时,触发器的操作看似有叁个未形成的事务在起效果。 通过多少个例子来讲学触发器和业务的传说。

开创二个表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

测试结果:

ca888会员登录 11ca888会员登录 12

从下面的测试景况,看出,Update Contact触发tr_Contact触发器操作,触发器里面包车型客车Rollback Tran 动作导致了触发器外面包车型大巴Update语句执行回滚,而Rollback Tran 语句前面包车型地铁Begin Tran语句,首借使利用于保持总体育赛事情的完整性。为了更能懂得这一历程,小编模拟了二个触发器中的事务先河终结进程。

ca888会员登录 13

图4.

在SQL Server 二零零七 和 SQL Server 2009方面,能够看到如图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

ca888会员登录 14ca888会员登录 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

 

ca888会员登录 16

 

这边,你是还是不是察觉多少个很有趣的标题,在触发器理,执行Insert ContactHIST在此之前,@@Trancount=1,执行Insert后,@@Trancount依然为1,触发器外面Update Contact后,@@Trancount就成为了2,。那里能够通晓成,你在触发器里面,发出1个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

 

ca888会员登录 17

此处,能够看来工作在触发器中Rollback,又没有打开新的政工,导致整个批处理就半途而返,不会继续执行触发器外面的Rollback Tran操作。倘诺,你在触发器中运用Begin Tran …… Commit Tran格式,那么触发器Commit Tran不会潜移默化到外围的事体;上面描述二种普遍触发器四川中华工程公司作的图景:

ca888会员登录 18ca888会员登录 19ca888会员登录 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 2007环境下,发生的结果区别。

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:自定义错误变量

暗中同意意况下一旦实施二个业务中出现错误,则只回滚错误操作语句(便是说那句不执行了,算不上回滚),错误处从前或之后的科学操作语句还是会被交付。如:

版权声明:本文由ca888发布于程序人生,转载请注明出处:Golang Mysql笔记(四)--- 事务