事务(Transaction)是并发控制的基本单位。通过事务,SQL Server能将逻辑相关的一组操作绑定在一起,以便服务器保持数据的完整性。
1.事务简介
事务反映了现实世界中需要以一个完整的单位提交的一项工作。事务是一个逻辑工作单元,它必须完整地执行,或者全都不执行(使数据库保持不变),它是一个不可分割的工作单位。事务处理是保证数据库一致性状态的重要方法。
例如,在银行的转账业务中,从账户A中提取一万元,存入账户B中,这两个操作或者完整地被执行,或者全不执行,不允许有中间状态存在。换句话说,像银行转账这类业务是不允许只完成一部分的,只从账户A中提取一万元,或者只向账户B中存入一万元,都将是错误的。
数据库的一致性状态是指所有数据都满足数据完整性约束条件的状态。
最常见的事务处理是由二次或多次数据库操作组成。一次数据库操作相当于在事务处理中的一个SQL语句。
为了保证数据库的一致性状态,SQL Server必须控制和保证事务的执行能够符合数据库的完整性约束条件。
2.事务处理控制语句
SQL Server通过事务控制语句,把SQL Server语句集合分组后,形成独立的逻辑工作单元。
事务处理控制语句有3个:
●BEGIN TRANSACTION。
●COMMIT TRANSACTION。
●ROLLBACK TRANSACTION。
几点说明:
●在SQL Server中,通常一个事务是以BEGIN TRANSACTION开始,到ROLLBACK TRANSACTION或一个相匹配的COMMIT TRANSACTION之间的所有语句序列。
●ROLLBACK表示要撤销该事务已做的一切操作,回滚到事务开始的状态。
●COMMIT表示提交事务中的一切操作,使得对数据库的改变生效。
●在SQL Server中,对事务的管理包含3个方面:
①事务控制语句。使用户或者程序员能把一系列Transact-SQL语句作为逻辑上的一个语句来处理。
②锁机制(Locking)。封锁正被一个事务修改的数据,防止其他用户访问到不一致的数据。
③事务日志(Transaction Log)。使事务具有可恢复性。
3.事务编程
对事务的编程技术主要是通过事务控制语句来实现。
例2-89 采用事务编程实现为课程号是“K001”的加10%的分数,为课程号是“K008”的减15%的分数,要求除非两条UPDATE语句全部执行,否则,“成绩表”中的记录值不会发生部分改变,如图2-102所示。
图2-102 事务编程
读一读
1.约束的定义
为了防止数据库中存在不符合语义规定的数据,防止因错误信息的输入、输出而造成无效的操作或错误信息,SQL Server系统采用了约束、规则、默认和事处理务等手段进行限制。其中约束是用来对用户输入到表或字段中的值进行限制的。
在SQL Server系统中,约束的定义主要是通过CREATE TABLE语句或ALTER TABLE语句来实现的。使用CREATE TABLE语句,是在建立新表的同时定义约束。使用ALTER TA-BLE语句,是向已经存在的表中添加约束。
约束可以是字段级约束,也可以是表级约束。字段级约束是把约束放在某个字段列上,且约束仅对该字段列起作用;表级约束是把约束放在表中的多个字段列上。
1)使用CREATE TABLE语句创建约束的语法格式如下:
其中的参数含义参见前面的CREATE TABLE语句的参数解释。
2)使用ALTER TABLE语句添加约束的语法格式如下:
其中的参数含义参见前面的ALTER TABLE语句的参数解释。
2.默认
默认是一种数据库对象。在数据库中建立一个默认对象并把该默认对象绑定到表字段或用户定义的数据类型时,如果用户在插入记录时没有明确地提供数据值,便自动使用默认对象并将其插入所绑定的字段中,在用户定义数据类型的情况下,则是插入到使用这个自定义数据类型的所有字段中。
使用CREATE DEFAULT语句时,需要注意以下几点:
●只能在当前数据库中创建默认对象。在一个数据库中,默认对象名称对于所有者来说必须是唯一的。
●单个批处理中,CREATE DEFAULT语句不能与其他Transact-SQL语句组合使用。
●默认对象的值必须与字段数据类型兼容。如果默认对象的值与其绑定到的字段不兼容,则在尝试插入默认对象的值时,SQL Server将生成错误信息。
●如果默认对象的值对于它所绑定的字段而言太长,该值就会被截断。
●建立一个同名的默认对象时,必须取消对该默认对象的绑定并删除该默认对象。
●如果字段同时有默认对象和规则与之关联,则默认对象的值不能违反规则。与规则冲突的默认对象将永远不能插入字段,每次试图插入这样的默认对象的值时,SQL Serv-er都会生成错误信息。
绑定默认对象时注意:
●不能将默认值绑定到timestamp数据类型的字段、带IDENTITY属性的字段或已经有DEFAULT约束的字段,也不能将默认值绑定到SQL Server的数据类型上。
●在某些情况下,需要使用“[”和“]”字符作为分隔标识符来分隔标识符。(www.xing528.com)
●如果默认值和要绑定的字段不兼容,那么在试图插入默认值时(不是绑定时)SQL Server将返回错误信息。
●在不取消绑定现有默认值的情况下,可以使用sp_bindefault将新默认值绑定到字段或用户定义的数据类型上,此时原有的默认值将被新默认值替代。
●当绑定成功时,系统存储过程sp_bindefault的返回值为0,绑定失败时为1。
●将一个默认值绑定到表中字段后,在以下场合会使用默认值。
●非显式地插入默认值:如果没有给该字段提供输入项,则该字段自动用默认值填充。
●显式地插入默认值:在INSERT语句中使用DEFAULT VALUES或DEFAULT关键字来插入默认值。
●如果在创建字段时指定NOT NULL并且没有为其创建默认值,则当用户未能为该字段输入值时,就会生成错误信息。
3.规则
规则是一种数据库对象,当把它绑定到字段或用户定义的数据类型时,使用这种方式可以提供与CHECK约束相同的功能。CHECK约束是用来限制字段值的首选标准方法,CHECK约束比规则更为简明,但规则的功能更加强大,在一个字段上只能应用一个规则,但是可以应用多个CHECK约束。CHECK约束是作为CREATE TABLE或ALTER TABLE语句的一部分来指定的,而规则是作为单独的数据库对象建立的,必须绑定到字段或用户定义的数据类型上才能完成。
使用系统存储过程sp_bindrule绑定规则时应注意以下几点:
●规则不能绑定到系统数据类型上。
●规则必须与表字段的数据类型相兼容,但不能绑定到数据类型为text、image和times-tamp的字段上。
●一个新的规则可以直接绑定到表字段或用户定义的数据类型上,而不必事先解除原先绑定在该字段或数据类型上的规则。
●当一个字段上同时绑定有规则和默认值时,默认值应该满足规则的要求。从数据库中删除一个规则值时,可以分为以下两种情况来处理:
●如果这个规则尚未绑定到字段或用户定义的数据类型上,可以使用DROP RULE语句来删除。
●如果已经将这个规则绑定到表字段或用户定义的数据类型上,必须首先使用系统存储过程sp_unbindrule来解除该规则在表字段或用户定义的数据类型上的绑定,然后使用DROP RULE语句来删除该规则。
4.锁机制
一个数据库事务中可能包括多个输入/输出操作,最终结果将使数据库从一个一致性状态到达另一个一致性状态,即在事务执行之前或之后数据库将处于一致性的状态。然而,在事务的执行期间,数据库可能暂时处于一个不一致性的状态。
若在数据库不一致性状态时读取数据,就有可能产生不一致性问题。解决这类问题的常用方法是对所修改的对象进行封锁。
(1)封锁
封锁是数据库中一个重要技术。在事务执行期间,例如进行更新操作时,数据库可能出现暂时的不一致性,利用封锁技术就能够有效地防止其他事务读不一致性的数据。其他事务必须等到此事务解锁(Unlock)之后才能访问该数据。
可封锁的对象有字段、记录、表和数据库等。
SQL Server具有自动和强制封锁的功能。
SQL Server可以使用不同的封锁方式。基本的封锁类型有以下3种。
●共享锁(Share Lock):共享锁又称为读锁,简称S锁。如果事务T对数据对象X加上共享锁,则其他事务只能对X再加上共享锁,不能加排他锁,从而保证了其他事务可以读X,但在事务T释放X上的锁之前不能对X做任何修改。
●排他锁(Exclusive Lock):排他锁又称为写锁,简称X锁。如果事务T对数据对象Y加上排他锁,则只允许事务T独占数据项Y,其他任何事务都不能对Y加任何类型的锁,直到T释放Y上的锁,从而避免其他事务读取不一致的数据。
●更新锁(Update Lock)
简称U锁。用来预定要对某对象施加X锁,它允许其他事务读,但不允许再施加U锁或X锁。当被读取的对象被更新时,则升级为X锁。U锁一直到事务结束时才能被释放。
当一个事务要从数据库中读数据,且没有任何其他事务在这个数据上加排他锁时,可以赋予共享锁。当一个事务要写一个数据项,且没有任何其他事务在这个数据项上加任何类型的锁时,可以赋予排他锁。
由共享锁和排他锁的原理可知,锁的状态有4种,分别是无锁、共享(读)锁、排他(写)锁和更新锁。
由锁的性质可知:读操作(如SELECT)获得共享锁;写操作(如INSERT、DELETE)获得排他锁;而更新(Update)操作可分解为一个读操作和一个写操作,故首先获得更新锁,然后再升级为排他锁。
例如,在创建索引时,如果创建的是[NONCLUSTERED]索引,则系统添加共享锁,如果创建的是[CLUSTERED]索引,则系统添加排他锁。
封锁的对象可以是逻辑单元,也可以是物理单元,即封锁的对象可以是数据库、表、行和列等逻辑单元,也可以是页、块等物理单元。封锁对象的大小称为封锁的粒度。
虽然封锁可以避免数据的不一致性,但也可能引起死锁问题,即两个事务彼此等待对方打开锁住的数据。
(2)死锁
下面通过例子来了解一下死锁的概念。
当两个事务Trans1和Trans2在下列状态时,将产生死锁。
●Trans1:存取数据项X和Y。
●Trans2:存取数据库Y和X。
如果事务Trans1封锁了数据项X,事务Trans2封锁了数据项Y,则Trans1等待Trans2释放Y上的锁,Trans2等待Trans1释放X上的锁。因此Trans1和Trans2都无限地等待对方打开锁住的数据项,即发生死锁。SQL server提供了自动发现并解除死锁的机制。
当SQL Server发生死锁时,会选择进程累计的CPU时间最少者所对应的用户,作为“被抛弃者”,以让其他用户能继续执行。此时,SQL Server发送错误号1205(即@@error=1205)给被抛弃者。
为尽可能避免死锁的发生,用户应该遵循以下原则:
●在所有的事务中都按同一顺序来访问各个表。尽可能利用存储过程来完成一个事务,以便能保证对各表的访问次序都是一致的。
●事务应该尽量小且应尽快提交。
●尽量避免人工输入操作出现在事务中。
●尽量避免同时执行诸如INSERT、UPDATE和DELETE等数据修改语句。归纳总结
通过这次任务的实践,了解了数据库完整性的含义,掌握了通过约束、默认、规则和事务处理保护数据库完整性的方法,避免了数据库中的数据出现错误。
免责声明:以上内容源自网络,版权归原作者所有,如有侵犯您的原创版权请告知,我们将尽快删除相关内容。