Oracle有很多值得学习的地方,这里我们主要介绍Oracle锁存器,包括介绍Oracle的读一致性机制等方面。Oracle锁的机制,分Oracle锁存器和锁两种。锁存器是用来保护对内存结构的访问,比如对DB BUFFER中块的锁存器申请,只有在DBWN完成后,这些DB BUFFER块被解锁。然后用于其它的申请。
Oracle锁存器不可以在进程间共享,锁存器的申请要么成功要么失败,没有锁存器申请队列。主要的Oracle锁存器有SHARED POOL锁存器,LIBRARY CACHE锁存器,CACHE BUFFERS LRU CHAIN锁存器,CACHE BUFFERS CHAINS锁存器,REDO ALLOCATION锁存器,REDO COPY锁存器。
Oracle的锁是用来保护数据访问的,锁的限制比锁存器要更宽松,比如,多个用户在修改同一表的不同行时,可以共享一个表上的一个锁,锁的申请可以按照被申请的顺序来排队等候,然后依次应用,这种排队机制叫做队列(ENPUEUE),如果两个服务器进程试图对同一表的同一行进行加锁,则都进入锁的申请队列,先进的加锁成功,后面的进程要等待,直到前一个进程解锁才可以加锁,这叫做锁的争用,而且一旦加锁成功,这个锁将一直保持到用户发出COMMIT或ROOLBACK命令为止。
如果两个用户锁定各自的一行并请求对方锁定的行的时候将发生无限期等待即死锁,死锁的发生都是由于锁的争用而不是锁存器的争用引起的,Oracle在遇到死锁时,自动释放其中一个用户的锁并回滚此用户的改变。正常情况下发生锁的争用时,数据的最终保存结果由SCN来决定哪个进程的更改被最终保存。两个用户的服务器进程在申请同一表的多个行的锁的时候是可以交错进入锁的申请队列的。只有其中发生争用才会进行等待。创建表时指定的MAXTRANS参数决定了表中的一个数据块同时最多可以被几个事务锁定。
下面来讲一下Oracle的读一致性机制,Oracle的读一致性保证了事务之间的高度隔离性。下面是几个关于回滚段读一致性和死锁的事例:
一、大SELECT,小UPDATE
A会话—-Select * from test;—-设scn=101—-执行时间09:10:11
B会话—–Update test set id=9999999 where id=1000000—-设scn=102—–执行时间09:10:12
我们会发现B会话会在A会话前完成,A会话中显示的ID=100000是从回滚段中读取的,因为A会话在读到ID=1000000所在的BLOCK时发现BLOCK上有事务信息,因此要从回滚段中读,如果UPDATE在SELECT读到此BLOCK之前已经COMMIT,则SELECT读到此BLOCK时发现其BLOCK上没有事务信息,但是会发现其BLICK的SCN比SELECT自己的SCN大,因此也会利用回滚段进行重构。根据当前块上所有的itl找到相应的undo地址,重构出之前的block image,之前的那个block又含有自己的itl信息.如果这个before image中对应的scn不满足查询,又会根据undo生成beforebeforeimage,这样不断往复,直到构造出符合查询的scn的block返回结果,或者系统实在无法根据undo构造出符合查询的block,,报ora-01555的错误为止….。需要强调的是读一致性是通过对当前整个块利用回滚段(当前块上的所有ITL记录的所有回滚段地址)进行递归重构到过去某一时间点或某一SCN的块的一致性快照。而不是只针对块中一部分ITL记录在回滚段中递归查找来完成的,一定要理解递归重构与递归查找是完全不同的两个概念。Oracle回滚段确保了事务的高度的隔离性。即只要回滚段足够大,那么一个SELECT不管执行多长,它读取的所有数据都将是在这条SELECT语句开始执行瞬间这个时间点的值,而不会被其它用户在SELECT读取期间对数据是否做过修改而影响。
二、大UPDATE,小SELECT
A会话—-Update test set id=1;—-设scn=101—-执行时间09:10:11
B会话—–select * from test where id=1000000—-设scn=102—–执行时间09:10:12
我们会发现B会话会在A会话前完成,B会话中显示的ID=1000000是从BLOCK中直接读取的,因为B会话在读到ID=1000000所在的BLOCK时,A会话还没有来得及对其锁定,因此B会话既不会发现BLOCK上有事务信息,也不会发现BLOCK上的SCN比SELECT的大,因此会从BLOCK中直接读取,如果SELECT在UPDATE锁定此BLOCK后才发出,B会话读到此BLOCK时发现其BLOCK上有事务信息,因此会从回滚段中读取。
三、大UPDATE,小UPDATE
A会话—-Update test set id=1;—-设scn=101—-执行时间09:10:11
B会话1—–Update test set id=999999 where id=1000000—-设scn=102—–执行时间09:10:12
B会话2—– select * from test where id=2—-设scn=103—–执行时间09:10:14
B会话3—– update test set id=3 where id=2—-设scn=104—–执行时间09:10:15
我们会发现B会话1会完成,A会话将一直等待,因为B会话1会先于A会话锁定ID=1000000所在的BLOCK,并改写头部的事务信息,A会话在试图锁定此BLOCK时,发现其上有事务信息,将会一直等待B会话1事务结束后再行锁定,B会话2查询到的ID=2是从回滚段中读取的而不是从BLOCK中直接读出来的。因为A会话已将ID=2的BLOCK锁定,并写入了回滚段,从B会话3可以证明这一点,B会话3发出后,B会话3会收到死锁的信息,死锁的原因是A会话在等待B会话对ID=1000000所在的BLOCK解锁,现在B会话又在等待A会话对ID=2所在的BLOCK解锁,因此形成死锁,因此证明ID=2所在的BLOCK已被A会话锁定,然后A会话也会收到死锁的信息。以上介绍Oracle锁存器。
我们一直都在努力坚持原创.......请不要一声不吭,就悄悄拿走。
我原创,你原创,我们的内容世界才会更加精彩!
【所有原创内容版权均属TechTarget,欢迎大家转发分享。但未经授权,严禁任何媒体(平面媒体、网络媒体、自媒体等)以及微信公众号复制、转载、摘编或以其他方式进行使用。】
微信公众号
TechTarget
官方微博
TechTarget中国