转自:html
http://www.cnblogs.com/moss_tan_jun/archive/2011/11/26/2263988.html数据库
在数据库中有时候须要把多个步骤的指令看成一个总体来运行,这个总体要么所有成功,要么所有失败,这就须要用到事务。数据结构
事务由若干条T-SQL指令组成,而且全部的指令做为一个总体提交给数据库系统,执行时,这组指令要么所有执行完成,要么所有取消。所以,事务是一个不可分割的逻辑单元。app
事务有4个属性:原子性(Atomicity)、一致性(Consistency)、隔离性(Isolation)以及持久性(Durability),也称做事务的ACID属性。ide
原子性:事务内的全部工做要么所有完成,要么所有不完成,不存在只有一部分完成的状况。函数
一致性:事务内的而后操做都不能违反数据库的而后约束或规则,事务完成时有内部数据结构都必须是正确的。spa
隔离性:事务直接是相互隔离的,若是有两个事务对同一个数据库进行操做,好比读取表数据。任何一个事务看到的全部内容要么是其余事务完成以前的状态,要么是其余事务完成以后的状态。一个事务不可能遇到另外一个事务的中间状态。日志
持久性:事务完成以后,它对数据库系统的影响是持久的,即便是系统错误,从新启动系统后,该事务的结果依然存在。code
显示事务就是用户使用T-SQL明确的定义事务的开始(begin transaction)和提交(commit transaction)或回滚事务(rollback transaction)htm
自动提交事务是一种可以自动执行并能自动回滚事务,这种方式是T-SQL的默认事务方式。例如在删除一个表记录的时候,若是这条记录有主外键关系的时候,删除就会受主外键约束的影响,那么这个删除就会取消。
能够设置事务进入隐式方式:set implicit_transaction on;
隐式事务是指当事务提交或回滚后,SQL Server自动开始事务。所以,隐式事务不须要使用begin transaction显示开始,只需直接失业提交事务或回滚事务的T-SQL语句便可。
使用时,须要设置set implicit_transaction on语句,将隐式事务模式打开,下一个语句会启动一个新的事物,再下一个语句又将启动一个新事务。
经常使用T-SQL事务语句:
开始事务,而@@trancount全局变量用来记录事务的数目值加1,能够用@@error全局变量记录执行过程当中的错误信息,若是没有错误能够直接提交事务,有错误能够回滚。
回滚事务,表示一个隐式或显示的事务的结束,对数据库所作的修改正式生效。并将@@trancount的值减1;
回滚事务,执行rollback tran语句后,数据会回滚到begin tran的时候的状态
--开始事务 begin transaction tran_bank; declare @tran_error int; set @tran_error = 0; begin try update bank set totalMoney = totalMoney - 10000 where userName = 'jack'; set @tran_error = @tran_error + @@error; update bank set totalMoney = totalMoney + 10000 where userName = 'jason'; set @tran_error = @tran_error + @@error; end try begin catch print '出现异常,错误编号:' + convert(varchar, error_number()) + ', 错误消息:' + error_message(); set @tran_error = @tran_error + 1; end catch if (@tran_error > 0) begin --执行出错,回滚事务 rollback tran; print '转帐失败,取消交易'; end else begin --没有异常,提交事务 commit tran; print '转帐成功'; end go
在程序中,有时候完成一些Transact-SQL会出现错误、异常信息。若是咱们想本身处理这些异常信息的话,须要手动捕捉这些信息。那么咱们能够利用try catch完成。
TRY…CATCH 构造包括两部分:一个 TRY 块和一个 CATCH 块。若是在 TRY 块中所包含的 Transact-SQL 语句中检测到错误条件,控制将被传递到 CATCH 块(可在此块中处理该错误)。
CATCH 块处理该异常错误后,控制将被传递到 END CATCH 语句后面的第一个 Transact-SQL 语句。若是 END CATCH 语句是存储过程或触发器中的最后一条语句,控制将返回到调用该存储过程或触发器的代码。将不执行 TRY 块中生成错误的语句后面的 Transact-SQL 语句。
若是 TRY 块中没有错误,控制将传递到关联的 END CATCH 语句后紧跟的语句。若是 END CATCH 语句是存储过程或触发器中的最后一条语句,控制将传递到调用该存储过程或触发器的语句。
TRY 块以 BEGIN TRY 语句开头,以 END TRY 语句结尾。在 BEGIN TRY 和 END TRY 语句之间能够指定一个或多个 Transact-SQL 语句。CATCH 块必须紧跟 TRY 块。CATCH 块以 BEGIN CATCH 语句开头,以 END CATCH 语句结尾。在 Transact-SQL 中,每一个 TRY 块仅与一个 CATCH 块相关联。
TRY...CATCH 使用错误函数来捕获错误信息:
ERROR_NUMBER() 返回错误号。
ERROR_MESSAGE() 返回错误消息的完整文本。此文本包括为任何可替换参数(如长度、对象名称或时间)提供的值。
ERROR_SEVERITY() 返回错误严重性。
ERROR_STATE() 返回错误状态号。
ERROR_LINE() 返回致使错误的例程中的行号。
ERROR_PROCEDURE() 返回出现错误的存储过程或触发器的名称。
示例
错误消息存储过程
if (object_id('proc_error_info') is not null) drop procedure proc_error_info go create proc proc_error_info as select error_number() '错误编号', error_message() '错误消息', error_severity() '严重性', error_state() '状态好', error_line() '错误行号', error_procedure() '错误对象(存储过程或触发器)名称'; go
示例:用异常处理错误信息
简单try catch示例
begin try select 1 / 0; end try begin catch exec proc_error_info; --调用错误消息存储过程 end catch go
示例:异常能处理的错误信息
简单try catch示例,没法处理错误
begin try select * * from student; end try begin catch exec proc_error_info; end catch go
简单try catch示例,不处理错误(不存在的表对象)
begin try select * from st; end try begin catch exec proc_error_info; end catch go
异常处理,能处理存储过程(触发器)中(不存在表对象)的错误信息
if (object_id('proc_select') is not null) drop procedure proc_select go create proc proc_select as select * from st; go begin try exec proc_select; end try begin catch exec proc_error_info; end catch go
示例:没法提交的事务
--建立临时用表 if (object_id('temp_tab', 'u') is not null) drop table temp_tab go create table temp_tab( id int primary key identity(100000, 1), name varchar(200) ) go begin try begin tran; --没有createTime字段 alter table temp_tab drop column createTime; commit tran; end try begin catch exec proc_error_info;--显示异常信息 if (xact_state() = -1) begin print '会话具备活动事务,但出现了导致事务被归类为没法提交的事务的错误。' + '会话没法提交事务或回滚到保存点;它只能请求彻底回滚事务。' + '会话在回滚事务以前没法执行任何写操做。会话在回滚事务以前只能执行读操做。' + '事务回滚以后,会话即可执行读写操做并可开始新的事务。'; end else if (xact_state() = 0) begin print '会话没有活动事务。'; end else if (xact_state() = 1) begin print '会话具备活动事务。会话能够执行任何操做,包括写入数据和提交事务。'; end end catch go
示例:处理异常日志信息
--异常、错误信息表 if (object_id('errorLog', 'U') is not null) drop table errorLog go create table errorLog( errorLogID int primary key identity(100, 1), --ErrorLog 行的主键。 errorTime datetime default getDate(), --发生错误的日期和时间。 userName sysname default current_user, --执行发生错误的批处理的用户。 errorNumber int, --发生的错误的错误号。 errorSeverity int, --发生的错误的严重性。 errorState int, --发生的错误的状态号。 errorProcedure nvarchar(126), --发生错误的存储过程或触发器的名称。 errorLine int, --发生错误的行号。 errorMessage nvarchar(4000) ) go --存储过程:添加异常日志信息 if (object_id('proc_add_exception_log', 'p') is not null) drop proc proc_add_exception_log go create proc proc_add_exception_log(@logId int = 0 output) as begin set nocount on; set @logId = 0; begin try if (error_number() is null) return; if (xact_state() = -1) begin print '会话具备活动事务,但出现了导致事务被归类为没法提交的事务的错误。' + '会话没法提交事务或回滚到保存点;它只能请求彻底回滚事务。' + '会话在回滚事务以前没法执行任何写操做。会话在回滚事务以前只能执行读操做。' + '事务回滚以后,会话即可执行读写操做并可开始新的事务。'; end else if (xact_state() = 0) begin print '会话没有活动事务。'; end else if (xact_state() = 1) begin print '会话具备活动事务。会话能够执行任何操做,包括写入数据和提交事务。'; end --添加日志信息 insert into errorLog values(getDate(), current_user, error_number(), error_severity(), error_state(), error_procedure(), error_line(), error_message()); --设置自增值 select @logId = @@identity; end try begin catch print '添加异常日志信息出现错误'; exec proc_error_info;--显示错误信息 return -1; end catch end go --处理异常信息示例 declare @id int; begin try begin tran; --删除带有外键的记录信息 delete classes where id = 1; commit tran; end try begin catch exec proc_error_info;--显示错误信息 if (xact_state() <> 0) begin rollback tran; end exec proc_add_exception_log @id output end catch select * from errorLog where errorLogID = @id; go