4.5事务

在SQL Server 2008中,事务是一个很重要的概念。事务在SQL Server中相当于一个工作单元,使用事务可以确保同时发生的行为与数据有效性不发生冲突,并且维护数据的完整性,确保SQL数据的有效性。

4.5.1  事务概述

事务的概念是现代数据库理论的核心概念之一。事务是单个的工作单元,是数据库中不可再分的基本部分。所谓事务就是用户对数据库进行的一系列操作的集合。对于事务中的操作要么全部完成,要么全部不完成。

SQL-Server系统具有事务处理功能,能够保证数据库操作的一致性和完整性。例如由于数据库是可共享的信息资源,当出现多个用户同时在某一时刻访问和修改同一数据库中的同一部分数据内容时,可能由于一个用户的行为,造成多个用户使用的数据可能变得无效。为了解决这种问题,SQL Server使用事务可以确保同时发生的行为与数据有效性不发生冲突,而且这些数据同进也可以被其他用户看到。

事务中一旦发生任何问题,整个事务就会重新开始,数据库也将返回到事务开始前的状态。先前发生的任何操作都会被取消,数据也恢复到原始状态。事务完成的话,便会将操作结果应用到数据库。所以无论事务是否完成或是否重新开始,事务总是确保数据库的完整性。

l   在Microsoft SQL Server 2008中,SQL Server可以将事务以下列4种模式运行,主要有:自动提交事务:每条单独的语句都是一个事务。它是SQL默认的事务管理模式,每个T-SQL语句完成时,都被提交或回滚。

l   显示事务:每个事务均以BEGINTRANSACTION语句显示开始,以COMMIT或ROLLBACK语句显示结束

l   隐式事务:在前一个事务完成时新事务隐式启动,但每个事务仍以COMMIT或ROLLBACK语句显示完成

l   批处理级事务:只能应用于多个活动结果集(MARS),在MARS会话中启动的Transact-SQL显示或隐式事务变为批处理级事务。当批处理完成时没有提交或回滚的批处理级事务将自动由SQL Server进行回来

例如使用T-SQL语言的UPDATE语句插入表数据,就可以被看作SQL Server的单个事务来运行,例如下面语句所示:


UPDATE [BookDateBase].[dbo].[Books]
   SET [bigClass]='文学'
,[SmallClass]='纪实文学'
,[Bcount]=-12
 WHERE Bnum='9787512500983'
GO


当运行该更新语句时,SQL Server认为用户的意图是在单个事务中同时修改行“大类(BigClass)”、“小类(SmallClass)”和“库存量(Bcount)”的数据。假设,在“库存量(Bcount)”列上不允许值小于0的约束,那么更新列“库存量(Bcount)”的操作就会失败,这样全部更新操作都无法实现。由于三条插入语句同在一个UPDATE语句中,所以SQL Server将这三个更新操作作为同一个事务来执行,当一个更新败后,其他操作便一起失败。

如果用户希望三个更新能够被独立地执行,则可以将上述语句改写成为如下所示的形式:


UPDATE [BookDateBase].[dbo].[Books]
   SET [Bcount]=-12
 WHERE Bnum='9787512500983'
 
 UPDATE [BookDateBase].[dbo].[Books]
   SET [SmallClass]='纪实文学'
 WHERE Bnum='9787512500983'
 
 UPDATE [BookDateBase].[dbo].[Books]
   SET [bigClass]='文学'
 WHERE Bnum='9787512500983'


这样做的目的是,即使对约束列的更新失败,也对其他列的更新没有影响,因为这是三个不同的事务处理操作。

4.5.2  ACID属性

SQL Server中,ACID属性用来标识事务的特性。事务是作为单个逻辑工作单元执行的一系列操作。一个逻辑工作单元必须有四个属性,称为原子性、一致性、隔离性和持久性 (ACID) 属性,只有这样才能成为一个事务。

1.原子性(Atomicity)

原子性是用于描述事务的必须工作单元;当事务结束时,对于事务内的所有数据操作,要么全都执行,要么都不执行。例如银行转账,转帐的过程中出现错误,整个事务将会回滚。只有当事务中的所有部分都成功执行了,才将事务写入数据库并使变化永久化。

2.一致性(Consistency)

事务在系统完整性中实施一致性,保证系统的任何事务最后都处于有效状态来实现。再看一下银行转帐的例子,在帐户资金转移前,帐户处于有效状态。如果事务成功地完成,并且提交事务,则帐户处于新的有效的状态。如果事务出错,终止后,帐户返回到原先的有效状态。即当许多用户同时使用和修改同样的数据时,事务必须保持其数据的完整性和一致性。

3.隔离性(Isolation)

在隔离状态执行事务,使它们好像是系统在给定时间内执行的唯一操作。如果有两个事务,运行在相同的时间内,执行相同的功能,事务的隔离性将确保每一事务在系统中认为只有该事务在使用系统。这种属性有时称为串行化,为了防止事务操作间的混淆,必须串行化或序列化请求,使得在同一时间仅有一个请求用于同一数据。

  从理论上说,一个事务绝不会遇到另一个事务内的状态,但实际上,SQL Server允许通过选择隔离级来改变这种状态

4.持久性(Durability)

持久性意味着一旦事务执行成功,在系统中产生的所有变化将是永久的。持久性的概念允许开发者认为不管系统以后发生了什么变化,完成的事务是系统永久的部分。

4.5.3  管理事务

SQL Server 提供很多与事务处理相关的语句,使用这些语句可以开始和终止事务、设置事务属性、推迟约束执行、在从新开的位置设置断点等。T-SQL使用下列四种语句来管理事务:

l   BEGIN TRAN:设置起始点。

l   COMMIT TRAN:使事务成为数据库中永久的、不可逆转的一部分。

l   ROLLBACK TRAN:本质上说想要忘记它曾经发生过。

l   SAVE TRAN:创建一个特定标记符,只允许作部分回滚。

在将它们组合成一个事务之前,先分别看一下它们各自的内容

1.BEGIN TRAN语句

BEGIN TRAN核心目的在于表示这一点是事务的起点。如果因为某些原因不能或不想提交事务,那么这一点就是将所有数据库操作回滚到起点。也就是说,就数据而言,任何超出该点范围的没有被提交的事务本质上都会被忘记。其语法结构如下所示:


BEGIN {TRAN |TRANSACTION}
[ { transaction_name | @tran_name_variable }
[ WITH MARK [ 'description'] ]
]
[;]


该语法中各参数的含义如下所示。

l   Transaction_name表示事务的名称。Transaction_name 必须符合标识规则,但标识符所包含的字符数不能大于32。仅在最外在面的BEGIN…COMMIT或BEGIN…ROLLBACK嵌套语句对中使用事务名。

l   @tran_name_variable 用户定义的、含有有效事务名称的变量的名称。必须用char、varchar、nchar或nvarchar数据类型声明变量。如果传递给该变量的字符多于32位个,则仅使用前面的32个字符;其余的字符将被截断。

WITH MARK['description'] 指定在日志中标记事务。Description是描述该标记的字符串。如果description是Unicode字符串,那么在将长于255个字符的值存储到msdb.dbo.logmarkhistory表之前,先将其截断为255个字符。如果description为非Unicode字符串,则长于510个字符的值将被截断为510个字符。

BEGIN TRANSACTION 语句用于声明开始一个本地事务。如果遇上错误,在BEGIN TRANSACTION 之后的所有数据改动都能进行回滚,以将数据返回到已知的一致状态。另外,事务还可以嵌套使用,例如下面语句所示:


USE BookDateBase
BEGIN TRAN
INSERT INTO [BookDateBase].[dbo].[Books]
     VALUES
('9787512500983'
,'1988--我想和你谈谈这个世界'
,'韩寒'
,'国际文化出版公司'
,'2010-09-01'
,'20.00'
,'小说'
,'中国当代小说'
,20
,'韩寒写过的最好的小说')
COMMIT TRANSACTION
ROLLBACK TRANSACTION


提交一个嵌套事务并不会将来自该事务的修改永久地写入到数据库中,只是让那些修改可供外层事务使用。

2.COMMIT TRAN

COMMIT TRAN表示完整的事务结束。在发生COMMIT TRAN时,系统就认为事务是持久的,也就是说,事务的影响现在是永久的,而且即使系统失败也持续下去。

COMMIT [  TRAN  |  TRANSACTION  ] [ transaction_name | @tran_name_varable ]
COMMIT [WORK]

语句中各参数的作用如下所示:

l   Transaction_name该参数可忽略。Transaction_name 指定由前面的BEGIN TRANSACTION 分配的事务名称。

l   @tran_name_variable 用户定义的、含有有效事务名称的变量的名称。必须用char、varchar、nchar或nvarchar数据类型声明变量。如果传递给该变量的字符多于32位个,则仅使用前面的32个字符;其余的字符将被截断。

“撤消”事务的唯一方法是执行一条新事务,从功能上来说,该事务是第一个事务的反转。

3.ROLLBACK TRAN

ROLLBACK TRANSACTION 语句用于当事务发生错误时进行回滚操作,从而恢复数据库至原始状态。其语法结构为:


ROLLBACK [ TRAN | TRANSACTION ]
[transaction_name | @tran_name_variable | savepoint_name | @savepoint_variable]
ROLLBACK [WORK]


各参数及语句说明如下:

l   Transaction_name要回滚的事务名称。

l   @tran_name_variable 用户定义的、包含有效事务名称的变量的名称。必须用char、varchar、nchar或nvarchar数据类型声明变量。

l   Savepoint_name当条件回滚只影响事务的一部分时,可使用savepoint_name.

l   @savepoint_variable用户定义的、包含有效保存点名称的变量的名称。必须用char,varchar,nchar或nvarchar 数据类型声明变量。

l   ROLLBACK WORK 语句 总是回退到嵌套事务系列当中的第一个事务(最外层事务)。

从相关的BEGIN语句开始发生的所有事情本质上都会被忘记。

4.SAVE TRAN

SAVE TRAN 语句允许部分地提交一个事务,同时仍能回滚这个事务的其余部分。其语法格式为:


SAVE { TRAN | TRANSACTION }{ savepoint_name | @savepoint_variable }


各参数的含义如下:

l   Savepoint_name  分配给保存点的名称。保存点名称必须符合标识符的规则,但长度不能超过32个字符。

l   @savepoint_variable 包含有效保存点名称的用户定义变量的名称。必须用char、varchar、nchar或nvarchar数据类型声明变量。如果长度超过32个字符,也可以传递到变量,但只使用前32个字符。

用户可以在事务内设置保存点或标记。保存点可以定义在按条件取消某个事务的一部分后该事务可以返回到的一个位置。记住,回滚时清除保存点-也就是说,即使有5个保存点,一旦执行了ROLLBACK,那么这5个保存点也都会消失。可以重新设置新的保存点,并回滚到那些点上,但无论是哪个保存点都会在回滚时消失。

4.5.4  分布式事务

SQL Server 不仅支持本地事务,而且还支持分布式事务。所谓分布式事务,是指对多个数据库中的数据进行修改操作的事务。这些数据库可以是本地的SQL Server 数据库,也要以是其他链接服务器上的数据库。

分布式事务由一个称为分布式事务协调程序的SQL Server构件来管理。在 Transact-SQL 中启动的分布式事务的结构相对比较简单:

l   Transact-SQL 脚本或应用程序连接执行启动分布式事务的 Transact-SQL 语句。

l   执行该语句的 Microsoft SQL Server 成为事务中的主控服务器。

l   然后脚本或应用程序对链接的服务器执行分布式查询,或对远程服务器执行远程存储过程。

l   当执行了分布式查询或远程过程调用后,主控服务器将自动调用 MS DTC 以便登记分布式事务中链接的服务器和远程服务器。

l   当脚本或应用程序发出 COMMIT 或 ROLLBACK 语句时,主控 SQL Server 将调用 MS DTC 管理两阶段提交过程,或者通知链接的服务器和远程服务器回滚其事务。