
并发控制与恢复技术.doc
5页实验四并发控制与恢复技术一、 实验目的1) 掌握利用并发控制技术解决rh于并发操作带来的数据不一致性问题2) 掌握数据库的恢复技术二、 实验内容1) 构造对数据读写造成不一致的操作2) 解决由于并发操作引起的数据不一致性问题3) 事务故障的恢复4) 利用数据库后备副木恢复三、 实验准备1•可串行化调度是什么?2. 并发操作可能会带来哪些数据不一致性问题?&丢失更新(lost update)T1T21、读出A二162、读出A二163、AGA-1 写冋 A二 154、A<-A-l 写回 A=15b・读“脏”数据(dirty read)T1T21、读出 C=100cec*2 写冋C2、读出02003、 ROLLBACKc恢复为100:3、写回C=200c.不可重复读(non-repeatable read)T1T21、读出A=50 读出B=100 求和=1502、读岀B=100B《B*23>读出A=50 读出B=200 和二250 (验算不对)上述问题都会引起数据的不一致性我们把事务准备接受不一致数据的级别称为隔离级别 隔离级别是一个事务必须与其它事务进行隔离的程度较低的隔离级别可以增加并发,但代 价是降低数据的正确性。
相反,较高的隔离级别可以确保数据的正确性,但可能对并发产生 负面影响应用程序要求的隔离级别确定了 SQL Server使用的锁定行为SQL定义了下列 四种隔离级别,SQL Server支持所有这些隔离级别:• READ UNCOMMITTED-一未提交读(事务隔离的最低级别,仅可保 证不读取物理损坏的数据)• READ COMMITTED---提交读(SQL Server 默认级别)• REPEATABLE READ-一可重复读• SERIALIZABLE-—可串行读(事务隔离的最高级别,事务Z间完 全隔离)用法:SET TRANSACTION ISOLATION LEVEL{ READ COMMITTEDREAD UNCOMMITTEDREPEATABLE READSERIALIZABLE13 .事务的基本操作耍点&事务的起始点BEGIN TRAN [ SACTION ] [ transaction_name |@tran_name_ variable …说明:transaction_name是给事•务分配的名称transaction_name必须遵循标识符规则, 但是不允许标识符多于32个字符。
仅在嵌套的BEGIN... COMMIT或BEGIN... ROLLBACK语 句的最外语句对上使用事务名name variable是用户定义的、含有有效事务名称的 变量的名称必须用char、varchor、nchar或nvarchar数据类型声明该变量例:BEGIN TRAN T1UPDATE tablel ...BEGIN TRAN M2UPDATE table2 ...SELECT * from tablelCOMMIT TRAN M2UPDATE table3COMMIT TRAN T1b・提交事务COMMIT [ TRAN [ SACTION ] [ transaetion_name | ^tran_name_variable~\ ] 下血的示例在图书的截止当前销售额超过$&000时,增加支付给作者的预付款BEGIN TRANSACTIONUSE pubsGOUPDATE titlesSET advanee = advanee * 1.25WHERE vtd_sales > 8000GO COMMITc. ROLLBACK TRANSACTION 将事务回滚语法 ROLLBACK [ TRAX [ SACTION ] [ transaction_name \ @ tran_name_ variable--四、实验方案1 •可参考下面的脚本自行设计创建测试用数据库和表。
创建测试用数据库testCREATE DATABASE testGO一创建测试用表USE testGOCREATE TABLE 帐户表(帐号 CHAR (4),余额TNT)GO往表中插入记录'A' , 100'B' ,2002.开启两个查询分析器程序,模拟两个并行的事务进行操作参考下血的例了自行构造查询 语句,模拟数据不一致性的三种问题a. 丢失更新一在第一个连接中执行以下语彳-JBEGIN TRANUPDATE帐户表SET余额二101 WHERE帐号二*WAITFOR DELAY '00:00:10'--等待 10 秒COMMIT TRAN一接着马上使用第二连接执行下面的语彳JBEGIN TRANUPDATE 帐户表 SET 余额二 102 WHERE 帐号COMMIT TRAX由于SQL Server默认级别为READ COMMITTED,我们会发现第二个连接里面的事务不能 立刻执行,必须等待第一连接的事务完成Z后才能执行下去这样就避免了 “丢失更 新”的问题,否则的话就会产生“丢失更新”的问题了白行设计:将事务的隔离级别设置为未提交读(READ UNCOMMITTED),看看结果如何?b. 读“脏”数据当事务的隔离级别为未提交读(READ UNCOMMITTED)的时候,允许脏读。
一在第一个连接中执行以下语句BEGIN TRANUPDATE 帐户表 SET 余额二 103 WHERE 帐号二'A'WATTFOR DELAY <00:00:10,—等待 10 秒UPDATE 帐户表 SET 余额=104 WHERE 帐号二'A'COMMIT TRAN一接着马上使用第二连接执行下面的语句SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTEDBEGIN TRANSELECT余额FROM帐户表WHERE帐号二,A'COMMIT TRAN我们会发现第二个连接的语句会立即返回,结果是103,但是它读取的是脏数据自行设计操作:把第二个连接的事务隔离级别设置为READ COMMITTED. REPEATABLE READ或者SERIALIZABLE,看看结果如何?c. 不可重复读(non-repeatable read)当事务的隔离级别为未提交读(READ UNCOMMITTED)或者READ COMMITTED的时候, 将会出现不可重复读的问题请测试下面这个例了(假设帐号A的余额为100):—在第一个连接中执行以下语句SET TRANSACTION ISOLATION LEVEL READ COMMITTED一或者 SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTEDBEGIN TRANSELECT余额FROM帐户表WHERE帐号二WAITFOR DELAY <00:00:10,--等待 10 秒SELECT余额FROM帐户表WHERE帐号二,A'COMMIT TRAN—接着马上使用第二连接执行下面的语句BEGIN TRANUPDATE帐户表SET余额二10 WHERE帐号二
白行设计:把连接一的事务隔离级别设置为REPEATABLE READ或者SERIALIZABLE, 看看结果如何?3. 事务故障的恢复通常情况下,应该把一个事务处理封闭在单个的批处理中例如下面这段程序:BEGIN TRANSACTIONINSERT帐户表(…)VALUES (…)IF @@ERROR=OBEGINPRINT 'INSERT WAS SUCCESSFUL CONTINUING'UPDATE帐户表SET帐号二WHERE余额二'…'DELETE帐户表WHERE帐号二'…'COMMIT TRANSACTION (观察实验结果)ENDELSEBEGINPRINT ' PUBLISHER INSERT FAILEDROLLING BACK TRANSACTION,ROLLBACK TRANSACTION (观察实验结果)END『I行设计:请构造操作不能成功执行的悄况(如违反了原来的完整性设置),以测试 事务的冋滚4. 白行设计实验步骤,利用数据库后备副木进行数据库恢复操作。
