在一般的数据库系统中,对于事务的并发处理一般是遵循二级封锁协议。而二级封锁协议是在一级封锁协议之上定制的。
一级封锁协议的要求是:事务T在修改数据R之前必须先对其加X锁,直到事务结束才释放。一级封锁协议可以防止丢失修改,并保证事务T是可恢复的。在一级封锁协议中,如果仅仅是读数据而不进行修改是不加锁的,所以它不能保证可重复读和不读“脏”数据
二级封锁协议是在一级封锁协议的基础上加上在读取数据R之前必须先对其价S锁,读完即可释放,注意读完就释放,这样其实还是不能做到可重复读的。举个例子:
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
如果此时另一个并发事务更新了CUSTOMERS表,那么事务T1再次读表的话数据就会不一致,这就是不可重复读。
但是二级封锁协议防止出现丢失修改和读脏数据的情况。
下面说一下三级封锁协议
三级封锁协议是一级封锁协议的基础上加上读取数据R前必须对其加S锁并且到事务结束再释放。这样就可重复读了
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
在很多DBMS中例如SQL SERVER默认在事务中使用的二级封锁协议
即:
任何更新和插入操作都会在对象上加IX锁,在更新和插入的元组上加X锁,直到事务结束(因为这些操作已经影响了数据库的内容,而且有可能回滚)。所以任何其他并发事务虽然可以在此对象上加IS或IX锁,但是对应的S或X锁只能加在未加X锁的元组上。否则将会被挂起
从对象内读取某些元组,在读取时会在对象上加IS锁,在所读取的元组上加S锁,但是一旦读取结束便会释放掉。显然这样是不可重复读的,当然为了避免不可重复读,我们可以在语句后加一个 HOLDLOCK 这样可以使IS和S锁保持到事务结束,这样就可重复读了,如果这样那么默认的二级封锁协议就被我们扩展成三级封锁协议了。例如:
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
如果是这样呢?
UPDATE CUSTOMERS SET COMPANY = 'BBB' WHERE CUST_NUM = 2102
这是可以执行的,因为它需要加X锁在2102这个元组上,这个元组并没有被别的事务加锁
OK,假设我们一开始是这样执行的,那会怎样呢
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
此时:
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
以上只是简单地讨论了DBMS中的并发处理,如果有什么问题还希望大家指正,本文欢迎转载但是请注明出处
blog.csdn.net/lesky