通过程序案例讲解《数据库原理》课程中的并发控制
2018-12-21史胜利
史胜利
(包头师范学院信息科学与技术学院,内蒙古 014030)
0 引言
并发控制是《数据库原理》课程的重要概念,并发控制技术涉及到多用户共享和事务处理技术,对于深入理解事务的特性、数据的共享、多用户并发操作都有重要的意义。同时并发控制教学对教师来说也是一个难点,并发操作带来的数据不一致性有多种情况,要理解这些不一致情况需要多方面知识,不仅仅涉及到一些SQL语句,还可能涉及到多用户访问、事务的隔离性和一致性等,往往需要一些具体的案例才能理解。
现有的《数据库原理》教材中都有并发控制的介绍,但内容上存在一些问题,例如都以理论讲解为主,使学生阅读起来困难;介绍的方法和概念很多,显得杂乱。这些问题可能在教师授课时也存在。教学中如果教师只讲理论,对于刚接触数据库的学生来说会有很大的难度,很难对并发操作出现的问题和并发控制方法留有深刻的印象。
1 程序案例
教师在讲解时可以使用程序案例把并发操作的整个过程都呈现出来,通过程序可以鲜活、生动的展示出现的问题,并很容易分析出产生问题的原因,既能引起学生的兴趣,又能使学生加深认识。下面给出一些讲解并发控制时的程序案例,代码是在MS SQL Server 2008中执行。
下面程序中用到的测试表Orders生成代码如下代码1:
CREATE TABLE Orders
(ID INT NOT NULL,Price FLOAT NOT NULL);
INSERT INTO Orders VALUES(10,10.00),(11,11.00),(12,12.00),(13,13.00),(14,14.00);
1.1 事务的原子性
事务是并发控制的基本单位,要理解并发控制首先要理解事务的原子性和事务处理命令。事务的原子性是事务中包括的诸操作要么都做,要么都不做。可以编写程序演示撤销事务部分操作的功能。下面的程序代码2演示事务的部分代码执行后出现错误,使用撤销语句恢复了数据。
begin
set xact_abort on;
begin try
begin tran
update orders set Price=Price+Price/10
where id=10;--执行成功
update orders set Price=Price+Price/0
where id=11;--除数为零错误,执行失败
commit tran
end try
begin catch
if xact_state()=-1--判断修改数据有没有出错
begin
rollbacktran;--事务执行中出错就撤销事务的所有操作
end
end catch
end
代码 2在 MS SQL Server 2008中执行,BEGIN TRAN、END TRAN、ROLLBACK TRAN语句分别用于标识事务开始、事务结束和撤销事务。上面的程序中事务的开始语句没问题,中间的操作会出现错误,这时使用回滚语句撤销了已执行的操作。
1.2 并发控制的必要性
并发控制讲解时需要让学生明白不实行并发控制会出现的问题。下面的程序代码3演示没有施行并发控制导致出现丢失更新问题。案例中使用两个用户同时连接数据库,然后两用户同时修改一个表中的数据时会引起丢失更新错误。
--第一步:用户A执行
SET TRANSACTION ISOLATION LEVEL READ COMMITTED
Begin tran
Declare@n float=0
Select@n=price from orders where id=10
Set@n=@n-5
waitfor delay'00:00:30'
Update orders set price=@n where id=10;
Commit tran
--第二步:用户B执行
SET TRANSACTION ISOLATION LEVEL READ unCOMMIT⁃TED
Begin tran
Declare@n int;
Select@n=price from orders where id=10;
Set@n=@n-5;
Update orders set price=@n where id=10;Commit tran
按上面先后步骤执行时,用户A在修改操作之前有一个30秒的等待,所以用户B先修改数据,然后用户A后修改,用户A把用户B修改的数据覆盖掉了。
1.3 读脏数据
下面代码4演示出现读脏数据问题。下面代码中用户A读取被用户B修改但未提交的数据,而用户B在后续操作中又撤消了修改,这就会使用户A读取的数据成为脏数据。
--第一步:用户A中执行修改orders表数据
BEGIN TRANSACTION
UPDATE Orders SET Price=Price+1 WHERE ID=10
--第二步:用户B中执行读取orders表数据
SET TRANSACTION ISOLATION LEVEL READ UNCOMMIT⁃
TED
SELECT ID,Price FROM Orders WHERE ID=10;
--第三步:用户A中执行撤销修改操作
ROLLBACK TRANSACTION
按上面代码4先后步骤执行后,用户B中读到的数据就成为脏数据。
1.4 不可重复读
下面代码演示并发操作时出现不可重复读问题。下面代码5中用户A先读取了数据,之后数据被用户B修改,然后用户A重新读取数据时和先前读取的就不一致了。
--第一步:用户A中执行读取orders表数据
SET TRANSACTION ISOLATION LEVEL COMMITTED--(1)
BEGIN TRANSACTION
SELECT ID,Price FROM Orders WHERE ID=10
--第二步:用户B中执行修改orders表数据
UPDATE Orders SET Price=Price+1 WHERE ID=10
--第三步:用户A中执行读取orders表数据
SELECT ID,Price FROM Orders WHERE ID=10
COMMIT TRANSACTION
按照上面代码5的步骤执行后会出现不可重复读问题,如果把第一步中语句(1)中的“COMMITTED”换成“REPEATABLE READ”就可避免不可重复读的错误
1.5 幻读
下面代码6演示并发操作时出现的幻读问题。用户A先读取了表数据,之后用户B在表中插入了数据,然后用户A重新读取表时得到的数据比以前多了。
--第一步:用户A中执行读取orders表数据
SET TRANSACTION ISOLATION LEVEL COMMITTED--(2)
BEGIN TRANSACTION
SELECT ID,Price FROM Orders
--第二步:用户B中执行向orders表插入数据INSERT INTO Orders VALUES(15,15.00)
--第三步:用户A中执行读取orders表数据
SELECT ID,Price FROM Orders
COMMIT TRANSACTION
按照上面步骤操作会出现幻读问题。上面代码如果把第一步中(2)的“COMMITTED”修改为“SERIALIZ⁃ABLE”,可避免出现幻读问题。
1.6 死锁
下面代码7演示出现死锁问题。有table1和ta⁃ble2两个表,用户A先修改了table1的数据,这样就持有table1的更新锁,接着用户B修改了table2的数据,又试图修改table1,但用户A还没有释放table1的更新锁,然后用户A又试图修改table2,但用户B这时持有table2的更新锁,这样用户A和用户B都会因等待对方占有的资源而陷入长期的等待状态。
--步骤1:用户A执行锁定了资源1
Begin tran
Update table1 set col1=2
--步骤2:用户B执行锁定了资源2,试图锁资源1
Begin tran
Update table2 set col1=2
Update table1 set col1=2
--步骤3:用户A执行试图锁资源2,发生死锁
Update table2 set col1=2
2 结语
并发控制是《数据库原理》课程中的重要内容,通过一些程序演示可展示事务并发时出现的问题和并发处理过程,可以使学生加深对事务原子性、隔离性、一致性的认识,对并发操作会出现的读脏数据、不可重复读、幻读、丢失更新有一个具体直观的印象,使抽象的概念具体化,教学效果会好得多。
[1]王珊,萨师煊等.数据库系统概论(第5版)[M].北京:高等教育出版社,2014.9
[2]David M.Kroenke、David J.Auer著,朱居正译.数据库原理(第7版):使用Access 2013演示与实践[M].北京:清华大学出版社,2015.6.
[3]安博教育集团.Oracle数据库系统[M].北京:电子工业出版社,2012.2.
[4]孟宪虎,马雪英等.大型数据库管理系统技术应用与实例分析—SQL Server 2005(第二版)[M].北京:电子工业出版社,2011.5.