南昌航空大学实验报告二0一年月日课程名称:数据库原理实验名称:数据库的并发控制与恢复备份班级:姓名:同组人:指导教师评定:签名:1、实验环境1、 Windows2000或以上版本;2、SQLServer2000或2005。
二、实验目的1.掌握数据库并发控制与恢复备份基础知识;2.掌握创建、修改、使用、数据库并发控制与恢复的不同方法。
三、实验步骤及参考源代码实验一:数据库并发控制1、丢失数据create table sales(客户代号char(5)primary key,数量int null)insert into sales values('A0001',0)create procedure modi_a asdeclare @i intdeclare @s1 intset transaction isolation level read committed select @i=1while(@i<=2000)beginbegin transelect @s1=数量from sales where客户代号='A0001'waitfor delay '00:00:00.002'update sales set数量=@s1+1 where客户代号='A0001'commit transelect @i=@i+1endcreate procedure modi_m asdeclare @i intdeclare @s1 intset transaction isolation level read committed select @i=1while(@i<=2000)beginbegin transelect @s1=数量from sales where客户代号='A0001'waitfor delay '00:00:00.002'update sales set数量=@s1-1 where客户代号='A0001'commit transelect @i=@i+1end同时运行存储过程modi_a和modi_m可以看到如下结果:本应该数量一栏应该是0的,说明数据发生了丢失数据。
将两个存储过程中事务中select语句改为:select @s1=数量 from sales with(tablockx) where 客户代号=’A0001’然后再次同时运行两个存储过程,结果如下:可以看到如果在存储过程中对数据加上独立锁后数量结果始终为0。
2、脏读数据create procedure dirt_wroll asdeclare @i intdeclare @s1 intset transaction isolation level read uncommitted select @i=1while(@i<=16000)beginselect @i=@i+1begin transelect @s1=数量from sales where客户代号='A0001'update sales set数量=@s1+1 where客户代号='A0001'rollback tranwaitfor delay '00:00:00.000'endcreate procedure dirt_r asdeclare @i intdeclare @s1 intset transaction isolation level read uncommitted select @i=1while(@i<=60000)beginselect @i=@i+1begin transelect @s1=数量from sales where客户代号='A0001'if(@s1<>1000)raiserror('发生了脏读!',16,1)commit tranend并行运行上面两个存储过程dirt_wroll和dirt_r看到如下结果:可知如果是这样的话,就会发生脏读的现象。
如果把上述的存储过程中的设置隔离级别的语句“set transaction isolation level read uncommitted”改为:“set transaction isolation level read committed”则就可以把问题解决了。
3、不可重复读create procedure rep_r asdeclare @i intdeclare @s1 intdeclare @s2 intset transaction isolation level read committed select @i=1while(@i<=3000)beginselect @i=@i+1begin transelect @s1=数量from sales where客户代号='A0001'waitfor delay '00:00:00.001'select @s2=数量from sales where客户代号='A0001'if(@s1<>@s2)raiserror('发生不可重复读!',16,1)commit tranendcreate procedure rep_w asdeclare @i intdeclare @s1 intdeclare @s2 intset transaction isolation level read committed select @i=1while(@i<=1000)beginbegin transelect @s1=数量from sales where客户代号='A0001'waitfor delay '00:00:00.002'update sales set数量=@s1+1 where客户代号='A0001'commit transelect @i=@i+1end以上两个存储过程同时运行的时候,会出现不可重复的现象,结果如下:预防这种结果的方法就是制定更高的事务隔离级别,如:repeatable read、snapshot、serializable.4、幻影问题create procedure huany_I asdeclare @i intset transaction isolation level repeatable read delete from sales where(客户代号='A1111')select @i=1while(@i<=1000)beginbegin traninsert into sales(客户代号,数量)values('A1111',1000)commit tranwaitfor delay '00:00:00.001'select @i=@i+1endcreate procedure huany_u asdeclare @i intdeclare @j intset transaction isolation level repeatable read select @i=1while(@i<=300)beginbegin tranupdate sales set数量=数量+3 where客户代号='A1111'select @j=0select @j=count(*)from sales where客户代号='A1111'and数量=1000if(@j>0)raiserror('发生了幻影现象!',16,1)commit tranwaitfor delay '00:00:00.001'select @i=@i+1end同时运行上面两个存储过程huany_I和huany_u会出现幻影现象,结果如下图:解决的方法为:指定事务级别为serializable。
5、抢答问题create procedure qiangxian1 asdeclare @i intset transaction isolation level read committedselect @i=1while(@i<=5000)beginbegin tranupdate sale set数量=数量+10000 where客户代号=@iif(@@error<>0)rollback tranelse commit tran select @i=@i+1end当同时执行像上面多个存储过程的时候就会出现抢答现象,记录的修改只能由先加锁的进程完成。
6、编号产生问题create procedure bhsc asdeclare @i intdeclare @s1 intset transaction isolation level read committedselect @i=1while(@i<=1500)beginbegin transelect @s1=max(客户代号)+1 from saleinsert into sale(客户代号,数量)values(@s1,@i)commit transelect @i=@i+1end多个以上的存储过程并行运行会出现编号重复现象,而且发现重复程度与并发程度成正比。
解决的办法法有:(1)设计编号产生事务一开始就加独立锁;(2)设计编号产生事务,其中采用插入后即查询重复编号情况,若发现重复,能进行反复尝试再插入;(3)利用一般数据库具有的identity字段来保障编号的唯一性。
下面的存储过程体现了前两种方法,当多个此存储过程同时运行时不会在发生编号重复现象。
create procedure bhsc2 asdeclare @i intdeclare @s1 intdeclare @kk intselect transaction level read committedwhile(@i<=1500)beginbegin transelect @s1=max(客户代号)+1 from sale with(tablock) insert into sale(客户代号,数量)values(@s1,@i)select @kk=count(*)from sale where客户代号=@1if @kk>=2 begin rollback tran continue endelse commit transelect @i=@i+1end7、手工加锁下并发事务读写冲突create procedure pmin asset transaction isolation level read committedselect @i=1while(@i<=500)beginbegin transelect @s1=数量from sales with(updlock)where客户代号='A0001'waitfor delay '00:00:00.003'update sales set数量=@s1-1 where客户代号='A0001'if(@@error<>0)rollback tranelse commit transelect @i=@i+1;endcreate procedure padd asset transaction isolation level read committedselect @i=1while(@i<=500)beginbegin transelect @s1=数量from sales with(updlock)where客户代号='A0001'waitfor delay '00:00:00.003'update sales set数量=@s1+1 where客户代号='A0001'if(@@error<>0)rollback tranelse commit transelect @i=@i+1;end实验二:数据库备份与恢复(1)备份数据库创建用于存放jxgl数据库完整备份的逻辑备份设备,然后备份整个jxgl 数据库use masterexec sp_addumpdevice'disk','jxgl_1','C:\Program Files\Microsoft SQLServer\MSSQL.1\MSSQL\Backup\jxgl_1.dat'backup database JXGL to jxgl_1创建一个数据库和日志的完整备份。