锁的类型:
基本的封锁类型有两种:排它锁(X锁)和共享锁(S锁)
X锁,是事务T对数据A加上X锁时,只允许事务T读取和修改数据A
S锁,是事务T对数据A加上S锁时,其他事务只能再对数据A加S锁,而不能加X锁,直到T释放A上的S锁。
若事务T对数据对象A加了S锁,则T就可以对A进行读取,但不能进行更新(S锁因此又称为读锁)。在T释放A上的S锁以前,其他事务可以再对A加S锁,但不能加X锁,从而可以读取A,但不能更新A。
更多锁的类型和隔离级别参考SQL 隔离级别
五类并发问题
丢失更新(一类丢失更新)
撤销一个事务时,把其他事务已提交的更新数据覆盖
A和B事务并发执行,A事务执行更新后,提交;B事务在A事务更新后,B事务结束前也做了对该行数据的更新操作,然后回滚,则两次更新操作都丢失了。
脏读
一个事务读到另一个事务未提交的更新数据
A和B事务并发执行,B事务执行更新后,A事务查询B事务没有提交的数据,B事务回滚,则A事务得到的数据不是数据库中的真实数据。也就是脏数据,即和数据库中不一致的数据。
不可重复读
一个事务读到另一个事务已提交的更新数据
A和B事务并发执行,A事务查询数据,然后B事务更新该数据,A再次查询该数据时,发现该数据变化了。
覆盖更新(二类丢失更新)
这是不可重复读中的特例,一个事务覆盖另一个事务已提交的更新数据
即A事务更新数据,然后B事务更新该数据,A事务查询发现自己更新的数据变了。
虚读(幻读)
一个事务读到另一个事务已提交的新插入的数据
A和B事务并发执行,A事务查询数据,B事务插入或者删除数据,A事务再次查询发现结果集中有以前没有的数据或者以前有的数据消失了。
三级封锁协议:
在运用X锁和S锁对数据对象加锁时,还需要约定一些规则。例如何时申请X锁或S锁、持锁时间、何时释放等。称这些规则为封锁协议(Locking Protocol)
一级封锁协议(对应read uncommited)
事务T在修改数据R之前必须先对其加X锁,直到事务结束才释放,事务结束包括正常结束(COMMIT)和非正常结束(ROLLBACK)。
一级封锁协议可以防止丢失修改,并保证事务T是可恢复的。使用一级封锁协议可以解决丢失修改问题。
在一级封锁协议中,如果仅仅是读数据不对其进行修改,是不需要加锁的,它不能保证可重复读和不读“脏”数据。
二级封锁协议(对应read commited)
在一级封锁协议之上,事务T在读取数据R之前必须先对其加S锁,读完后方可释放S锁。
二级封锁协议除防止了丢失修改,还可以进一步防止读“脏”数据。
但在二级封锁协议中,由于读完数据后即可释放S锁,所以它不能保证可重复读。
三级封锁协议(对应reapetable read)
在一级封锁协议之上,事务T在读取数据R之前必须先对其加S锁,直到事务结束才释放S锁。
三级封锁协议除防止了丢失修改和不读“脏”数据外,还进一步防止了不可重复读。
四级封锁协议(对应serialization)
四级封锁协议是对三级封锁协议的增强,其实现机制也最为简单,直接对事务中所读取或者更改的数据所在的表加表锁,也就是说,其他事务不能读写该表中的任何数据。这样五类并发问题都得以避免!