并发操作的不正确调度可能会带来丢失修改,不可重复读和读脏数据不一致等问题,不同的事务隔离级别分别在不同程度上解决了这一问题,为并发操作的正确调度提供一定的保证,本文介绍Read uncommitted(未提交读) Read committed(提交读) Repeatable read(可重复读) Serializable(可串行化),这四种事务隔离级别的封锁规则。 首先介绍X锁,S锁的概念。
X锁
X锁,又叫排他锁,写锁,若事务T对数据对象A加上X锁,则只允许T读取和修改A,其它事务都不能对A加任何类型的锁,直到T释放A上的锁。这就保证了其它事务在T释放A上的锁之前不能读取或修改A。
S锁
共享锁,读锁,若事务T对数据对象A加上S锁,则事务T可以读A但不能修改A,其它事务只能对A加S锁,而不能加X锁,直到T释放A上的S锁。这就保证了其它事务可以读A,但T释放A上的S锁之前不能对A做任何修改。
Read uncommitted(未提交读)
当事务设置了未提交读时,解决了丢失修改问题,事务T在修改数据之前必须先对其加X锁,直到事务结束才释放
当然,在操作仅仅是读数据的时候,读数据不会对其产生修改,则其不必等待也不需要加任何锁
所以,它不能保证不脏读数据,可重复读和无幻像读
Read committed(提交读)
解决了丢失和脏读问题。事务T在修改数据R之前必须先对其加X锁,直到提交事务才释放;事务T在读取数据R之前必须对其添加S锁,读完即可释放S锁
提交读保证运行在该隔离级别的事务不会读取到其他未提交事务所修改的数据。如果另外一个是事务正在更新数据,它所更新的数据上持有排他锁,那么此隔离级别上的事务在访问该数据之前必须等待其它事务其上的排他锁。同样地,此隔离级别上地事务必须在所访问地数据上至少放置共享锁。共享锁不会防止其它事务读取数据,但它会防止其它事务修改数据。
共享锁在数据发送给请求它地客户端之后就可以释放,它不需要保持到事务结束。由于读完就可释放S锁,所以它不能保证可重复读和无幻像读。
Repeatable read(可重复读)
解决了丢失修改,脏读和不可重复读的问题,但允许发生幻想读。事务T在修改数据R之前必须先对其加X锁,直到事务结束才释放;事务T在读取R之前必须先对其加S锁,直到事务结束才释放。
可保证一个事务如果再次访问同一数据,与此前访问相比,数据不会发生改变,换句话说,在事务两次同一数据之间,其它事务都不能修改数据。但可重复读允许发生幻想读
为保证可重复读,事务必须保持它的共享锁一直到事务结束。
没有其它事务能修改可重复读事务正在访问的数据,显然这会极大的降低系统的并发性。
Serializable(可串行化)
解决了,丢失修改,脏读,不可重复读和幻像读问题,即并发操作的四个不一致问题,为保证可串事务隔离级别必须遵守两段锁协议
两段锁协议::保证并发调度可串行性的封锁协议,要求事务分两个阶段提出加锁和解锁申请,在对任何数据进行读,写操作之前,首先要申请并获得对该数据的封锁,在释放一个封锁之后,事务不再申请和获得任何其它封锁
隔离级别 | 锁模式 | |
S锁 | X锁 | |
Read uncommited | 无 | 长 |
Read commited | 短 | 长 |
Repestable read | 长 | 长 |
Serializable | 长 | 长 |
并发操作带来的错误类型
丢失修改
两个事务T1和T2读入同一数据并修改,T2提交的修改结果破坏了T1的修改结果,导致T1的修改被丢失。丢失修改又称为写-写错误
脏读
事务T1修改某一数据,将其写回磁盘,事务T2读取同一数据后,T1由于某种原因被撤销,这时T1已经修改过的数据恢复原值,T2读到的数据就与数据库中的数据不一致,则T2读到的数据就是“脏”数据,即不正确的数据
不可重复读
事务T1读取某一数据之后,事务T2对其做了修改,当T2再次读取该数据时,得到与前次不同的值。不可重复读又称作读-写错误
幻像读
事务T2按一定条件读取了某些数据后,事务T1差入(或删除)了满足这些条件的数据,当T2再次按相同条件读取数据时,发现多了(少)一些数据