这是大三第一学期《数据库基础》的实验报告,总共15个实验,前12个百度文库都有,后面三个网上找不到都是我自己花了很多时间琢磨出来的,希望对大家,以及将来的我有所帮助!
了解四种异常事务状态(分别是脏读、不可重复读、丢失更新、死锁),理解发生异常事务状态的原理,以及我们要则么通过增加事务隔离级别来封锁,实现并发控制。当然随着事务隔离级别提升,所消耗的资源也变多,所以要根据实际情况选择隔离级别,也要预防死锁现象的发生。
当然sql server 2012版本自带预防机制,所以导致部分实验没法做,重点是理解异常产生的原理,以及如何防止异常的发生。
全部总结链接
SQL基础 (数据库、表、数据的增删改查、视图相关,以及所有实验报告源代码)
游标 (类似C++ 的 指针)
存储过程(类似 C++ 的自定义函数)
触发器 (类似 自定义的陷阱,或者说是监听器,满足某个条件了执行某个方法)
用户权限及权限管理 (类似Windows的多用户管理)
并发控制 (了解多个用户同时对数据造成错误的情况 和 解决方法)
数据恢复(当数据库数据丢失,相应的解决方法)
课程名称 数据库基础
实验项目 实验14 并发控制
实验要求:
- 独立完成本实验,以多个用户身份登录,创建管理多个事务。
- 设计一组操作产生“脏”读问题,然后通过封锁避免“脏”读问题。
- 设计一组操作产生不可重复读问题,然后通过封锁避免不可重复读问题。
- 设计一组操作产生丢失更新问题,然后通过封锁避免丢失更新问题。
- 设计一组产生死锁的操作,再利用相同顺序法有效的避免死锁。
- 在实验报告中要给出具体的操作步骤和过程,并针对各种情况做出具体的分析和讨论,很好的体会事务的性质和并发控制的作用。
实验过程
第一题:设计一组操作产生“脏”读问题,然后通过封锁避免“脏”读问题。
1.1概念:我个人觉得脏读就是A事务读到了B事务未提交的数据。(A事务修改数据1后,B事务读取了当前的数据1,然后A因为某种错误回档,导致B事务读取的数据错误)。通俗来说就是A事务放了B事务的鸽子。
1.2整体思路:
先运行一个事务A ( 1.修改课程学时数据为8 ; 2.等待20秒 ; 3.回滚数据,学时还原为6 ),在事务A的第二步等待的时候,运行事务B ( 1.查询学时; 2. 等待20秒; 3. 查询学时)。其中事务B第一次查询是事务A中间的等待期,所以学时为8,第二次查询在事务A结束后,所以学时为6.
1.3 代码截图:
首先我们在第一个查询页面运行以下代码:
图 1 查询窗口1 先更新学时为‘8 ’ 后回滚
代码解析:
以上第一行代码为:事务zwz1的开始标志
第二行代码:更新课程表中课程编号为1128的学时为8
第三行代码:等待20秒延迟
第四行代码:回滚第二行代码,恢复到该事务未执行的状态
第五行代码:查询课程表中课程编号为1128的所有信息
接下来在查询窗口2,执行以下代码:
图 2 查询窗口2 分别在事务A 等待期 和 结束后 查询学时
代码解析:
以上第一行代码为:在无锁的情况下查询课程表中课程编号为1128的所有信息(为错误信息)
第二行代码:等待20秒的时间
第三行代码:再次查询,发现数据不一致(本次为正确信息)
接下来是加封锁的情况:
图 3 加了写读锁后(不加也一样),窗口1回滚后 学时还是6 不变
注:和前面不加封锁对比,多了第一行代码,即加上一个“写读锁”,个人理解为“当事务A想读取某数据,必须要等当前其他事务修改完,才能读”
图 4 加了写读锁之后 事务B等事务A全部执行完毕后再执行 所以结果都是6
注:窗口二和前面不加封锁相比,也是多了第一行代码,运行的时候能明显感觉到运行了40秒,即等窗口1执行完毕后再执行窗口2的事务。
第二题:设计一组操作产生不可重复读问题,然后通过封锁避免不可重复读问题。
2.1 概念:事务A读某数据后,事务B将其修改,然后事务A再次读数据和之前的不一样。通俗理解为被调包。
2.2 总体思路:事务A读取1128号课程数据后,等待5秒,然后事务A再次读取该课程数据。其中事务B利用事务A的等待期,对该课程数据进行修改。
2.3代码截图:
图 5 事务A三部曲:读取数据 ;等待期 ; 读取数据 。发现数据不一致
图 6 事务B 在事务A等待期内 对数据进行修改
解决方案:设置隔离级别 :repeatable read(可重复读) 书本179页
思路:在原有基础上 增加封锁
图 7 事务A执行过程中 事务B无法插入 所以前后查询结果一致
图 8 事务B只能在事务A执行完毕后再执行 修改成功
图 9 事务B执行后 学时数据被修改
第三题:设计一组操作产生丢失更新问题,然后通过封锁避免丢失更新问题。
3.1概念:丢失更新我个人理解为事务A和事务B同时对该数据进行修改,假设事务A执行时间短,事务B执行时间长,那么事务B会覆盖事务A的修改结果。(换一种方式的放鸽子)
但是在SQL Server 2012中,不管是同一用户还是不同用户,都自带锁,即都是在先执行的事务执行完毕后,再执行另一个事务。
3.2总体思路 :
事务A先对学时数据查询(原先为6),再对学时进行修改(修改为8),最后5秒等待期再次查询(结果为8)。
事务B在事务A的等待期内开始执行(结果是等事务A结束再执行的),也先对学时数据查询(原先为6),再对学时进行修改(修改为10),最后5秒等待期再次查询(结果为10)
结果为事务B覆盖了事务A的更新,可我觉得这只是因为事务B比事务A晚执行的原因
3.3 代码截图:
图 10 刚开始 学时数据为 6
先执行事务A,紧接着执行事务B(相当于在事务A的等待期内执行)
图 11 可以视为 同时执行事务A和事务B
观察事务A 、事务B的执行结果:
图 12 事务A执行前数据为6 执行后数据为8
图 13 事务B执行前数据为8 执行后数据为10 说明和事务A互不干扰
这时候我们可以发现,事务B在事务A全部完成之后再执行,对事务A互不干扰 ,最后查看数据库中的数据为10.
图 14 数据库 课程表中的数据
第四题:设计一组产生死锁的操作,再利用相同顺序法有效的避免死锁。
4.1 概念 :就是你等我,我等你,导致互相一直等下去,卡死循环
4.2整体思路:
同样 sql server 2012也自带对死锁的预防,实验如下:
我先执行查询1(操作1,等待5秒,操作2),然后马上执行查询2(操作2,等待5秒,操作1),因为执行中间有五秒等待时间,查询1的第二个更新等待查询2执行完毕,查询2的第二个更新等待查询1执行完毕,构成死锁。
不过大概10秒钟之后,sql server 2012自动解开了死锁,即查询2做出让步,查询1全部执行。( &^^^& 太智能了)
4.3代码截图:
图 15 事务A被事务B让步 成功执行
图 16 事务B为了让步事务A,成为牺牲品,后半段执行失败
然后使用相同顺序法调换顺序之后:
图 17 事务A正常执行
图 18 事务B正常执行
即没有死循环,正常运行。