1. [问题1]
引入两个伪指令a=R(x)和W(b,X)。其中a=R(x)表示读取当前红包记录的ReceiverID字段(记为数据项X)到变量a中,W(b,X)表示将抢红包人的唯一标识b的值写入到当前红包记录的ReceiverID字段(数据项X)中,变量a为空值时才会执行W(b,X)操作。假设有多个人同时抢同一红包(即同时对一记录进行操作),用a
i=R
i(X)和W
i(b
i,X)表示系统依次响应的第i个人的抢红包操作。假设当前数据项X为空值,同时有三个人抢同一红包,则
(1)如下的调度执行序列:
a
1=R
1(X),a
2=R
2(X),W
1(b
1,X),W
2(b
2,X),a
3=R
3(X)
抢到红包的是第几人?并说明理由。
(2)引入共享锁指令SLock
i(X)、独占锁指令XLock
i(x)和解锁指令UnLock
i(X),其中下标i表示第i个抢红包人的指令。如下的调度执行序列:
SLock
1(X),a
1=R
1(X),SLock
2(X),a
2=R
2(X),XLock
1(X)…
是否会产生死锁?并说明理由。
(3)为了保证系统第一个响应的抢红包人为最终抢到红包的人,请使用上述(2)中引入的锁指令,对上述(1)中的调度执行序列进行修改,在满足2PL协议的前提下,给出一个不产生死锁的完整的调度执行序列。
(1)第2人。
对同一数据项的写入,先写的会被后写的值所覆盖。
(2)会产生死锁。
在执行序列SLock1(X),a1=R1(x),SLock2(X),a2=R2(X),XLock1(X)…中,XLockl(x)指令会因为当前X上已经有SLock2(X)所加的锁,因锁冲突而等待第2人释放锁,而随后会有XLock2(X)令等待第1人释放指令SLock1(X)所加的锁,相互等待形成死锁。
(3)执行序列:
XLock1(X),a1=R1(X),W1(b1,X),UnLock1(X),XLock2(X),a2=R2(X),UnLock2(X),XLock3(X),a3=R3(X),UnLock3(X) 注:答案不唯一
2. [问题2]
下面是用SQL实现的抢红包程序的一部分,请补全空缺处的代码。
CREATE PROCEDURE ScrambleRed (IN BatchNo VARCHAR(20), --红包批号
IN mecvrmo VARCHAR(20) ) --接收红包者ID
BEGIN
--是否已抢过此批红包
if exists( SELECT * FROM Red
WHERE BatchID = BatchNo AND ReceiverID = RecvrNo) then
return -1;
end if;
--读取此批派发红包中未领取的红包记录ID
DECLARE NonRecvedNo VARCHAR(30);
DECLARE NonRecvedRed CURSOR FOR
SELECT ID
FROM Red
WHERE BatchID = BatchNo AND ReceiverID IS NULL;
--打开游标
OPEN NonRecvedRed;
FETCH NonRecvedRed INTO NonRecvedNo;
while not error
--抢红包事务
BEGIN TRANSACTION;
//写入红包记录
UPDATE Red SET ReceiverID = RecvrNo
WHERE ID = NonRecvedNo AND ______;
//执行状态判定
if<修改的记录数>=1 then
COMMIT;
______;
return 1;
else
ROLLBACK;
end if;
______
end while;
--关闭游标
CLOSE NonRecvedRed;
return 0;
END
ReceiverID IS NULL
CLOSE NonRecvedRed
FETCH NonRecvedRed INTO NonRecvedNO
[解析] 本题考查事务并发控制及事务编程。
此类题目要求考生熟练掌握事务基本概念、事务并发控制实现原理和技术,以及事务程序的编写。
[问题1]
根据题目描述,抢红包操作是将抢红包人的ID写入到红包记录的ReceiverID字段。多人抢同一红包即为对同一数据项的读写操作。
(1)分析给定的调度执行序列:
a1=R1(X),a2=R2(X),W1(b1,X),W2(b2,X),a3=R3(X)
中,a1=R1(X),a2=R2(X)表示抢红包的第一、第二人读取数据项X,X当前值为空值,两人均可写入自己的ID值;而后的W1(b1,X),W2(b2,X)表示第一、第二人先后将自己的ID值写入X项,第一人写入的值会被随后第二人的写入值所覆盖,X的当前值为第二人ID;a3=R3(X)表示第三人读取X项的值,X的当前值非空(即第二人的ID),根据题目描述的规则“变量a为空值时才会执行W(b,X)操作”,第三人不能再写入自己的ID值。序列执行结束时,X项的值为第二人得ID,故抢到红包的为第二人。
(2)引入锁指令后的调度执行序列:
SLock1(X),a1=R1(X),SLock2(X),a2=R2(x),XLock1(X)…中,执行完指令SLock1(X),a1=R1(X),SLock2(X),a2=R2(X)后,数据项X上有事务T1(第一人的抢红包事务)和事务T2(第二人的抢红包事务)分别加的共享锁;随后的指令XLock1(X)为事务T1再对数据项加独占锁,此时数据项X上已有事务T2所加的共享锁。根据锁冲突规则,XLock1(X)指令加锁失败,事务T1处于等待状态,等待事务T2释放X上的共享锁;根据事务的程序逻辑,稍后事务T2也会运行XLock2(X)指令申请对X数据项加独占锁,同样的,事务T2会等待事务T1释放X上的共享锁,T1、T2两个事务相互等待对方释放锁,陷入死锁状态。
(3)为了保证系统第一个响应的抢红包人为最终抢到红包的人,抢红包事务可以在读取数据项X之前执行XLock(X)直接加独占锁,此后的抢红包事务对X项加锁,只能等待第一人的事务T1执行结束,此时数据项己写入第一人的ID值,后续事务读到非空值,无法再写入自己的ID。
直接使用XLock(x)后的指令序列为:XLock1(x),a1=R1(x),W1(b1,x),UnLock1(x),XLock2(X),a2=R2(X),UnLock2(X),XLock3(X),a3=R3(X),UnLock3(X)
[问题2]
本问题是用存储过程编写的抢红包事务程序。用户通过调用该存储过程完成抢红包操作。因此,存储过程先查询该用户是否已抢过此批次的红包;然后以游标的方式读取到此批次当前所有未抢的红包(可能是多个),以事务的方式对游标中的当前记录写入用户ID。由于多人同时抢红包,游标所查询到的未抢红包,可能在写入用户ID时,已经被其他人写入,故写入程序应该添加条件“ReceiverID值为空”,即第一处应填入“ReceiverID IS NULL”。如果出现两个及以上用户同时对同一条记录写入,此时会由DBMS进行并发控制,保证第一个响应的用户写入不被覆盖。
根据抢红包规则,一个用户只能抢到一批红包中的一个,因此成功抢到红包后(成功更新一条红包记录),应该退出程序,不能进入下一轮循环再去抢下一个红包。程序中使用了游标,在退出程序前应该关闭游标,因此第二处应该填写关闭游标的指令“CLOSENonRecvedRed”。
游标操作循环体中的最后一条指令应该是推进游标指针,故第三处应填写“FETCHNonRecvedRed INTO NonRecvedNo”。