小议数据库系统中的并发控制

来源:互联网 发布:好听的淘宝男装店名 编辑:程序博客网 时间:2024/04/30 08:18
在一般的数据库系统中,对于事务的并发处理一般是遵循二级封锁协议。而二级封锁协议是在一级封锁协议之上定制的。
一级封锁协议的要求是:事务T在修改数据R之前必须先对其加X锁,直到事务结束才释放。一级封锁协议可以防止丢失修改,并保证事务T是可恢复的。在一级封锁协议中,如果仅仅是读数据而不进行修改是不加锁的,所以它不能保证可重复读和不读“脏”数据
二级封锁协议是在一级封锁协议的基础上加上在读取数据R之前必须先对其价S锁,读完即可释放,注意读完就释放,这样其实还是不能做到可重复读的。举个例子:
BEGIN TRANSACTION T1 
--加S锁
SELECT * FROM CUSTOMERS
--释放S锁

如果此时另一个并发事务更新了CUSTOMERS表,那么事务T1再次读表的话数据就会不一致,这就是不可重复读。
但是二级封锁协议防止出现丢失修改和读脏数据的情况。

下面说一下三级封锁协议
三级封锁协议是一级封锁协议的基础上加上读取数据R前必须对其加S锁并且到事务结束再释放。这样就可重复读了

BEGIN TRANSACTION T1 
--加S锁
SELECT * FROM CUSTOMERS HOLDLOCK
--不释放S锁
--
此时如果有一个并发事务进行更新操作,因为无法获得x锁将会被挂起直到事务结束。

COMMIT TRANSACTION T1
--释放S锁

在很多DBMS中例如SQL SERVER默认在事务中使用的二级封锁协议
即:
任何更新和插入操作都会在对象上加IX锁,在更新和插入的元组上加X锁,直到事务结束(因为这些操作已经影响了数据库的内容,而且有可能回滚)。所以任何其他并发事务虽然可以在此对象上加IS或IX锁,但是对应的S或X锁只能加在未加X锁的元组上。否则将会被挂起
从对象内读取某些元组,在读取时会在对象上加IS锁,在所读取的元组上加S锁,但是一旦读取结束便会释放掉。显然这样是不可重复读的,当然为了避免不可重复读,我们可以在语句后加一个 HOLDLOCK 这样可以使IS和S锁保持到事务结束,这样就可重复读了,如果这样那么默认的二级封锁协议就被我们扩展成三级封锁协议了。例如:

BEGIN TRANSACTION T1 --开始一个事务
SELECT * FROM CUSTOMERS --从对象内选择某些元组,在选择时会加IS和S锁
--
读取结束便会释放掉IS和S锁

BEGIN TRANSACTION T2
UPDATE CUSTOMERS SET COMPANY = 'AAA' WHERE CUST_NUM = 2101 --这个事务是可以执行的,因为现在不存在任何锁

--在TI中再执行
UPDATE CUSTOMERS SET COMPANY = 'BBB' WHERE CUST_NUM = 2101
--这个操作将被挂起,因为T2已经在对象上加了IX锁,虽然T1需要的IX锁可以成功加在表上,但是因为它欲加在元组2101上的X锁与T2中已存在的X锁是不兼容的(在同一元组上),所以会被挂起。

如果是这样呢?
UPDATE CUSTOMERS SET COMPANY = 'BBB' WHERE CUST_NUM = 2102
这是可以执行的,因为它需要加X锁在2102这个元组上,这个元组并没有被别的事务加锁

OK,假设我们一开始是这样执行的,那会怎样呢

BEGIN TRANSACTION T1 --开始一个事务
SELECT * FROM CUSTOMERS HOLDLOCK--从对象内选择某些元组,在选择时会加IS和S锁
--
IS和S锁不会被释放直到事务结束为止
注意HOLDLOCK,它要求事务一直保持IS和S锁直到事务结束,这样默认的二级封锁协议被扩展成三级了
此时:
BEGIN TRANSACTION T2
UPDATE CUSTOMERS SET COMPANY = 'AAA' WHERE CUST_NUM = 2101
--这个操作会被挂起,因为T1已经在所有的元组上加了S锁,并且T1现在并没有提交或者回滚。

以上只是简单地讨论了DBMS中的并发处理,如果有什么问题还希望大家指正,本文欢迎转载但是请注明出处

blog.csdn.net/lesky

 
原创粉丝点击