oracle一个事务的完整流程收藏 oracle一个事务的完整流程分析

本文详细解析Oracle数据库中一个事务从开始到结束的全过程,涵盖SQL语句解析、数据读取、日志记录等多个核心步骤。
<h1 class="title_txt">
<img src="http://blog.youkuaiyun.com/images/authorship.gif" border="0" alt="原创" width="15" height="15">

oracle一个事务的完整流程分析
<cite class="fav_csdnstylebykimi"><a class="fav_csdnstylebykimi" title="收藏到我的网摘中,并分享给我的朋友">收藏</a>
</cite>

</h1>
<pre class="MsoNormal" style="margin: 0cm 1.25pt 0pt 0cm; text-indent: 0.1pt;"><span lang="EN-US"><span>author:skate</span>
</span>
</pre>
<pre class="MsoNormal" style="margin: 0cm 1.25pt 0pt 0cm; text-indent: 0.1pt;"><span lang="EN-US"><span>time:2010-09-01</span>
</span>
</pre>
<p><span lang="EN-US"><span>
</span>
</span>
</p>
<pre class="MsoNormal" style="margin: 0cm 1.25pt 0pt 0cm; text-indent: 0.1pt;"><hr></pre>
<pre class="MsoNormal" style="margin: 0cm 1.25pt 0pt 0cm; text-indent: 0.1pt;"><span style="font-size: small;"></span>
</pre>
<pre class="MsoNormal" style="margin: 0cm 1.25pt 0pt 0cm; text-indent: 0.1pt;"><span style="font-size: small;">在oracle客户端与服务端建立连接的,并把请求提交给oracle服务端以前分析过,参考如下:</span>
</pre>
<pre class="MsoNormal" style="margin: 0cm 1.25pt 0pt 0cm; text-indent: 0.1pt;"><span style="font-size: small;"><a href="http://blog.youkuaiyun.com/wyzxg/archive/2010/08/16/5815335.aspx">http://blog.youkuaiyun.com/wyzxg/archive/2010/08/16/5815335.aspx</a>
</span>
</pre>
<pre class="MsoNormal" style="margin: 0cm 1.25pt 0pt 0cm; text-indent: 0.1pt;"><span style="font-size: small;">今天主要分析下<span lang="EN-US">oracle</span>
<span style="">服务进程如何处理用户进程的请求</span>
</span>
</pre>
<pre class="MsoNormal" style="margin: 0cm 1.25pt 0pt 0cm; text-indent: 0.1pt;"><span style="font-size: small;"><span lang="EN-US"><strong>oracle</strong>
</span>
<span style=""><strong>服务进程如何处理用户进程的请求</strong>
</span>
</span>
</pre>
<pre class="MsoNormal" style="margin: 0cm 1.25pt 0pt 0cm; text-indent: 0.1pt;"><span style="font-size: small;"><span style=""><strong></strong>
</span>
</span>
</pre>
<pre class="MsoNormal" style="margin: 0cm 1.25pt 0pt 0cm; text-indent: 0.1pt;"><span style="font-size: small;"><span style=""><strong></strong>
</span>
</span>
</pre>
<pre class="MsoNormal" style="margin: 0cm 1.25pt 0pt 0cm; text-indent: 0.1pt;"><span style="font-size: x-small;"><span style=""><strong></strong>
</span>
</span>
</pre>
<pre class="MsoNormal" style="margin: 0cm 1.25pt 0pt 0cm; text-indent: 0.1pt;"><span style="font-size: x-small;"><span style=""><strong></strong>
</span>
</span>
</pre>
<pre class="MsoNormal" style="margin: 0cm 1.25pt 0pt 0cm; text-indent: 0.1pt;"><span style="font-size: x-small;"><span style=""><strong></strong>
</span>
</span>
</pre>
<pre class="MsoNormal" style="margin: 0cm 1.25pt 0pt 0cm; text-indent: 0.1pt;"><span style="font-size: x-small;"><span style=""><strong></strong>
</span>
</span>
</pre>
<pre class="MsoNormal" style="margin: 0cm 1.25pt 0pt 0cm; text-indent: 0.1pt;"><span style="font-size: x-small;"><span style=""><span style="font-size: small;">服务器进程在完成用户进程的请求过程中,主要完成如下7个任务:</span>
</span>
</span>
</pre>
<pre class="MsoNormal" style="margin: 0cm 1.25pt 0pt 0cm; text-indent: 0.1pt;"><span style="font-size: x-small;"></span>
</pre>
<pre class="MsoNormal" style="margin: 0cm 1.25pt 0pt 0cm; text-indent: 0.1pt;"></pre>
<pre class="MsoNormal" style="margin: 0cm 1.25pt 0pt 0cm; text-indent: 0.1pt;"><span style="font-size: x-small;"><span style=""><p class="MsoNormal" style="margin: 0cm 1.25pt 0pt 0cm; text-indent: 0.1pt;"><span style="color: #008000;"><span style="font-size: x-small;"><span style=""><span style="font-size: small;">0.sql语句的解析</span>
</span>
</span>
</span>
</p>
<p class="MsoNormal" style="margin: 0cm 1.25pt 0pt 0cm; text-indent: 0.1pt;"><span style="color: #008000;"><span style="font-size: x-small;"><span style=""><span lang="EN-US"><span style="font-size: x-small;"><span style="color: green;"><span style=""><span style="font-size: small;">1.数据块的读入db buffer</span>
</span>
</span>
</span>
</span>
</span>
</span>
</span>
</p>
<p class="MsoNormal" style="margin: 0cm 1.25pt 0pt 0cm; text-indent: 0.1pt;"><span style="color: #008000;"><span style="font-size: x-small;"><span style=""><span lang="EN-US"><span style="font-size: x-small;"><span style="color: green;"><span style="" lang="EN-US"><span style="font-size: x-small;"><span style="color: #008000;"><span style="font-size: small;">2.记日志</span>
</span>
</span>
</span>
</span>
</span>
</span>
</span>
</span>
</span>
</p>
<p class="MsoNormal" style="margin: 0cm 1.25pt 0pt 0cm; text-indent: 0.1pt;"><span style="color: #008000;"><span style="font-size: x-small;"><span style=""><span lang="EN-US"><span style="font-size: x-small;"><span style="color: green;"><span style=""><span lang="EN-US"><span style="color: #008000;"><span style="font-size: small;">3.为事务建立回滚段</span>
</span>
</span>
</span>
</span>
</span>
</span>
</span>
</span>
</span>
</p>
<p class="MsoNormal" style="margin: 0cm 1.25pt 0pt 0cm; text-indent: 0.1pt;"><span style="color: #008000;"><span style="font-size: x-small;"><span style=""><span lang="EN-US"><span style="font-size: x-small;"><span style="color: green;"><span style=""><span lang="EN-US"><span style=""><span style="font-size: small; color: #008000;"><span style="font-size: small;">4.本事务修改数据块</span>
</span>
</span>
</span>
</span>
</span>
</span>
</span>
</span>
</span>
</span>
</p>
<p class="MsoNormal" style="margin: 0cm 1.25pt 0pt 0cm; text-indent: 0.1pt;"><span style="color: #008000;"><span style="font-size: x-small;"><span style=""><span lang="EN-US"><span style="font-size: x-small;"><span style="color: green;"><span style=""><span lang="EN-US"><span style=""><span style="font-size: small; color: #008000;"><span style="font-size: x-small;"><span style="" lang="EN-US"><span style="font-size: x-small;"><span style="color: #008000;"><span style="font-size: small;">5.放入<span lang="EN-US">dirty list</span>
</span>
</span>
</span>
</span>
</span>
</span>
</span>
</span>
</span>
</span>
</span>
</span>
</span>
</span>
</span>
</p>
<p class="MsoNormal" style="margin: 0cm 1.25pt 0pt 0cm; text-indent: 0.1pt;"><span style="color: #008000;"><span style="font-size: x-small;"><span style=""><span lang="EN-US"><span style="font-size: x-small;"><span style="color: green;"><span style=""><span lang="EN-US"><span style=""><span style="font-size: small; color: #008000;"><span style="font-size: x-small;"><span style="" lang="EN-US"><span style="font-size: x-small;"><span style="color: #008000;"><span lang="EN-US"><span style="font-size: small;">6.用户commit或rollback</span>
</span>
</span>
</span>
</span>
</span>
</span>
</span>
</span>
</span>
</span>
</span>
</span>
</span>
</span>
</span>
</p>
<p class="MsoNormal" style="margin: 0cm 1.25pt 0pt 0cm; text-indent: 0.1pt;"><span style="color: #008000;"><span style="font-size: x-small;"><span style=""><span lang="EN-US"><span style="font-size: x-small;"><span style="color: green;"><span style=""><span lang="EN-US"><span style=""><span style="font-size: small; color: #008000;"><span style="font-size: x-small;"><span style="" lang="EN-US"><span style="font-size: x-small;"></span>
</span>
</span>
</span>
</span>
</span>
</span>
</span>
</span>
</span>
</span>
</span>
</span>
</p>
</span>
</span>
</pre>
<pre class="MsoNormal" style="margin: 0cm 1.25pt 0pt 0cm; text-indent: 0.1pt;"><span style="font-size: small;"><span style=""><strong></strong>
</span>
</span>
</pre>
<p style="text-indent: 0.1pt; margin-right: 1.25pt;"><span lang="EN-US"><span style="font-size: small;"></span>
</span>
</p>
<p style="text-indent: 0.1pt; margin-right: 1.25pt;"><span lang="EN-US"><span style="font-size: x-small;"><span style="color: #008000;"><span style="font-size: x-small;"><span style=""><span style="font-size: small;">0.sql语句的解析</span>
</span>
</span>
</span>
</span>
</span>
</p>
<p style="text-indent: 0.1pt; margin-right: 1.25pt;"><span lang="EN-US"><span style="font-size: x-small;"><span style="color: #008000;"><span style="font-size: x-small;"></span>
</span>
</span>
</span>
</p>
<p style="text-indent: 0.1pt; margin-right: 1.25pt;"><span lang="EN-US"><span style="font-size: x-small;"><span style="color: #008000;"><span style="font-size: x-small;"></span>
</span>
</span>
</span>
</p>
<p style="text-indent: 0.1pt; margin-right: 1.25pt;"><span lang="EN-US"><span style="font-size: x-small;"><span style="color: #008000;"></span>
</span>
</span>
</p>
<p style="text-indent: 0.1pt; margin-right: 1.25pt;"><span lang="EN-US"></span>
</p>
<p class="MsoNormal" style="margin: 0cm 1.25pt 0pt 0cm; text-indent: 0.1pt;"><span style="font-size: small;"><span style="">下面要讲</span>
<span lang="EN-US">oracle</span>
<span style="">服务器进程如可处理用户进程的请求,当一用户进程提交一个</span>
<span lang="EN-US">sql</span>
<span style="">时:</span>
<span lang="EN-US">update temp set a=a*2</span>
<span style="">;首先</span>
<span lang="EN-US">oracle</span>
<span style="">服务器进程从用户进程把信息接收到后,在</span>
<span lang="EN-US">PGA</span>
<span style="">中就要此进程分配所需内存,存储相关的信息,如在会话内存存储相关的登录信息等;服务器进程把这个</span>
<span lang="EN-US">sql</span>
<span style="">语句的字符转化为</span>
<span lang="EN-US">ASCII</span>
<span style="">等效数字码,接着这个</span>
<span lang="EN-US">ASCII</span>
<span style="">码被传递给一个</span>
<span lang="EN-US">HASH</span>
<span style="">函数,并返回一个</span>
<span lang="EN-US">hash</span>
<span style="">值,然后服务器进程将到</span>
<span lang="EN-US">shared pool</span>
<span style="">中的</span>
<span lang="EN-US">library cache</span>
<span style="">中去查找是否存在相同的</span>
<span lang="EN-US">hash</span>
<span style="">值,如果存在,服务器进程将使用这条语句已高速缓存在</span>
<span lang="EN-US">SHARED POOL</span>
<span style="">的</span>
<span lang="EN-US">library cache</span>
<span style="">中的已分析过的版本来执行,如果不存在,服务器进程将在</span>
<span lang="EN-US">CGA</span>
<span style="">中,配合</span>
<span lang="EN-US">UGA</span>
<span style="">内容对</span>
<span lang="EN-US">sql</span>
<span style="">,进行语法分析,首先检查语法的正确性,接着对语句中涉及的表,索引,视图等对象进行解析,并对照数据字典检查这些对象的名称以及相关结构,并根据</span>
<span lang="EN-US">ORACLE</span>
<span style="">选用的优化模式以及数据字典中是否存在相应对象的统计数据和是否使用了存储大纲来生成一个执行计划或从存储大纲中选用一个执行计划,然后再用数据字典核对此用户对相应对象的执行权限,最后生成一个编译代码</span>
<span style="">。</span>
<span lang="EN-US">ORACLE</span>
<span style="">将这条</span>
<span lang="EN-US">sql</span>
<span style="">语句的本身实际文本、</span>
<span lang="EN-US">HASH</span>
<span style="">值、编译代码、与此语名相关联的任何统计数据和该语句的执行计划缓存在</span>
<span lang="EN-US">SHARED POOL</span>
<span style="">的</span>
<span lang="EN-US">library cache</span>
<span style="">中。服务器进程通过</span>
<span lang="EN-US">SHARED POOL </span>
<span style="">锁存器(</span>
<span lang="EN-US">shared pool latch</span>
<span style="">)来申请可以向哪些共享</span>
<span lang="EN-US">PL/SQL</span>
<span style="">区中缓存这此内容,也就是说被</span>
<span lang="EN-US">SHARED POOL</span>
<span style="">锁存器锁定的</span>
<span lang="EN-US">PL/SQL</span>
<span style="">区中的块不可被覆盖,因为这些块可能被其它进程所使用。在</span>
<span lang="EN-US">SQL</span>
<span style="">分析阶段将用到</span>
<span lang="EN-US">LIBRARY CACHE</span>
<span style="">,从数据字典中核对表、视图等结构的时候,需要将数据字典从磁盘读入</span>
<span lang="EN-US">LIBRARY CACHE</span>
<span style="">,因此,在读入之前也要使用</span>
<span lang="EN-US">LIBRARY CACHE</span>
<span style="">锁存器(</span>
<span lang="EN-US">library cache pin</span>
<span style="">,</span>
<span lang="EN-US">library cache lock</span>
<span style="">)来申请用于缓存数据字典。</span>
</span>
</p>
<p class="MsoNormal" style="margin: 0cm 1.25pt 0pt 0cm; text-indent: 0.1pt;"><span lang="EN-US"><span style="font-size: small;"></span>
</span>
</p>
<p class="MsoNormal" style="margin: 0cm 1.25pt 0pt 0cm; text-indent: 0.1pt;"><span style="color: #008000;"><span style="font-size: small;"><span style="">到现在为止,这个</span>
<span lang="EN-US">sql</span>
<span style="">语句已经被编译成可执行的代码了,但还不知道要操作哪些数据,所以服务器进程还要为这个</span>
<span lang="EN-US">sql</span>
<span style="">准备预处理数据。</span>
</span>
</span>
</p>
<p class="MsoNormal" style="margin: 0cm 1.25pt 0pt 0cm; text-indent: 0.1pt;"></p>
<p class="MsoNormal" style="margin: 0cm 1.25pt 0pt 0cm; text-indent: 0.1pt;"><span style="color: #008000;"><span style="font-size: x-small;"><span style=""><span lang="EN-US"><span style="font-size: x-small;"><span style="color: green;"><span style=""><span lang="EN-US"><span style=""><span style="font-size: small; color: #008000;"><span style="font-size: x-small;"><span style="" lang="EN-US"></span>
</span>
</span>
</span>
</span>
</span>
</span>
</span>
</span>
</span>
</span>
</span>
</p>
<p class="MsoNormal" style="margin: 0cm 1.25pt 0pt 0cm; text-indent: 0.1pt;"><span style="color: #008000;"><span style="font-size: x-small;"><span style=""><span lang="EN-US"><span style="font-size: x-small;"><span style="color: green;"></span>
</span>
</span>
</span>
</span>
</span>
</p>
<p class="MsoNormal" style="margin: 0cm 1.25pt 0pt 0cm; text-indent: 0.1pt;"><span lang="EN-US"><span style="font-size: small;"></span>
</span>
</p>
<p class="MsoNormal" style="margin: 0cm 1.25pt 0pt 0cm; text-indent: 0.1pt;"><span lang="EN-US"><span style="font-size: x-small;"><span style="color: green;"><span style=""><span style="font-size: small;">1.数据块的读入db buffer</span>
</span>
</span>
</span>
</span>
</p>
<p class="MsoNormal" style="margin: 0cm 1.25pt 0pt 0cm; text-indent: 0.1pt;"><span lang="EN-US"><span style="font-size: x-small;"><span style="color: green;"></span>
</span>
</span>
</p>
<p class="MsoNormal" style="margin: 0cm 1.25pt 0pt 0cm; text-indent: 0.1pt;"><span lang="EN-US"><span style="font-size: x-small;"></span>
</span>
</p>
<p class="MsoNormal" style="margin: 0cm 1.25pt 0pt 0cm; text-indent: 0.1pt;"><span lang="EN-US"></span>
</p>
<p class="MsoNormal" style="margin: 0cm 1.25pt 0pt 0cm; text-indent: 0.1pt;"><span style="font-size: small;"><span lang="EN-US">Oracle</span>
<span style="">处理数据,都需要把数据读取到内存中(即</span>
<span lang="EN-US">db buffer</span>
<span style="">中),首先服务器进程要判断所需数据是否在<span lang="EN-US">db</span>
</span>
<span lang="EN-US">buffer</span>
<span style="">存在,如果存在且可用,则直接获取该数据,同时根据</span>
<span lang="EN-US">LRU</span>
<span style="">算法增加其访问计数;如果</span>
<span lang="EN-US">buffer</span>
<span style="">不存在所需数据,则要从数据文件上读取。首先服务器进程将在表头部请求</span>
<span lang="EN-US">TM</span>
<span style="">锁(保证此事务执行过程其他用户不能修改表的结构),如果成功加</span>
<span lang="EN-US">TM</span>
<span style="">锁,再请求一些行级锁(</span>
<span lang="EN-US">TX</span>
<span style="">锁),如果</span>
<span lang="EN-US">TM</span>
<span style="">、</span>
<span lang="EN-US">TX</span>
<span style="">锁都成功加锁,那么才开始从数据文件读数据,在读数据之前,要先为读取的文件准备好</span>
<span lang="EN-US">buffer</span>
<span style="">空间。服务器进程需要扫面</span>
<span lang="EN-US">LRU list</span>
<span style="">寻找</span>
<span lang="EN-US">free db buffer</span>
<span style="">,扫描的过程中,服务器进程会把发现的所有已经被修改过的<span lang="EN-US">db</span>
</span>
<span lang="EN-US">buffer</span>
<span style="">注册到</span>
<span lang="EN-US">dirty list</span>
<span style="">中,</span>
</span>
</p>
<p class="MsoNormal" style="margin: 0cm 1.25pt 0pt 0cm; text-indent: 0.1pt;"></p>
<p class="MsoNormal" style="margin: 0cm 1.25pt 0pt 0cm; text-indent: 0.1pt;"><span style="font-size: small;"><span style="">这些</span>
<span lang="EN-US">dirty buffer</span>
<span style="">会通过</span>
<span lang="EN-US">dbwr</span>
<span style="">的触发条件,随后会被写出到数据文件,找到了足够的空闲</span>
<span lang="EN-US">buffer</span>
<span style="">,就可以把请求的数据行所在的数据块放入到</span>
<span lang="EN-US">db buffer</span>
<span style="">的空闲区域或者覆盖已经被挤出</span>
<span lang="EN-US">LRU list</span>
<span style="">的非脏数据块缓冲区,并排列在</span>
<span lang="EN-US">LRU list</span>
<span style="">的头部,</span>
<span style="">也就是在数据块放入<span lang="EN-US">DB BUFFER</span>
之前也是要先申请<span lang="EN-US"><span lang="EN-US">db</span>
<span lang="EN-US">buffer</span>
</span>
中的锁存器,成功加锁后,才能读数据到<span lang="EN-US"><span lang="EN-US">db</span>
<span lang="EN-US">buffer</span>
</span>
。</span>
</span>
</p>
<p class="MsoNormal" style="margin: 0cm 1.25pt 0pt 0cm; text-indent: 0.1pt;"></p>
<p class="MsoNormal" style="margin: 0cm 1.25pt 0pt 0cm; text-indent: 0.1pt;"></p>
<p class="MsoNormal" style="margin: 0cm 1.25pt 0pt 0cm; text-indent: 0.1pt;"></p>
<p class="MsoNormal" style="margin: 0cm 1.25pt 0pt 0cm; text-indent: 0.1pt;"><span style="" lang="EN-US"><span style="font-size: x-small;"><span style="color: #008000;"><span style="font-size: small;">2.记日志</span>
</span>
</span>
</span>
</p>
<p class="MsoNormal" style="margin: 0cm 1.25pt 0pt 0cm; text-indent: 0.1pt;"><span style="" lang="EN-US"><span style="font-size: small;"></span>
</span>
</p>
<p class="MsoNormal" style="margin: 0cm 1.25pt 0pt 0cm; text-indent: 0.1pt;"><span style="font-size: small;"><span style="">现在数据已经被读入到<span lang="EN-US"><span lang="EN-US">db</span>
<span lang="EN-US">buffer</span>
</span>
了</span>
<span style="">,现在服务器进程将该语句所影响的并被读入<span lang="EN-US"><span lang="EN-US">db</span>
<span lang="EN-US">buffer</span>
</span>
中的这些行数据的<span lang="EN-US">rowid</span>
及要更新的原值和新值及<span lang="EN-US">scn</span>
等信息从<span lang="EN-US">PGA</span>
逐条的写入<span lang="EN-US">redo log buffer</span>
中。在写入<span lang="EN-US">redo log buffer</span>
之前也要事先请求<span lang="EN-US">redo log buffer</span>
的锁存器,成功加锁后才开始写入,当写入达到<span lang="EN-US">redo log buffer</span>
大小的三分之一或写入量达到<span lang="EN-US">1M</span>
或超过三秒后或发生检查点时或者<span lang="EN-US">dbwr</span>
之前发生,都会触发<span lang="EN-US">lgwr</span>
进程把<span lang="EN-US">redo log buffer</span>
的数据写入磁盘上的<span lang="EN-US">redo file</span>
文件中(这个时候会产生<span lang="EN-US">log file sync</span>
等待事件),已经被写入<span lang="EN-US">redo file</span>
的<span lang="EN-US">redo log buffer</span>
所持有的锁存器会被释放,并可被后来的写入信息覆盖,<span lang="EN-US">redo log buffer</span>
是循环使用的。<span lang="EN-US">Redo file</span>
也是循环使用的,当一个<span lang="EN-US">redo file </span>
写满后,<span lang="EN-US">lgwr</span>
进程会自动切换到下一<span lang="EN-US">redo file</span>
(这个时候可能出现<span lang="EN-US">log file switch</span>
(<span lang="EN-US">checkpoint complete</span>
)等待事件)。如果是归档模式,归档进程还要将前一个写满的<span lang="EN-US">redo file</span>
文件的内容写到归档日志文件中(这个时候可能出现<span lang="EN-US">log file switch</span>
(<span lang="EN-US">archiving needed</span>
))。</span>
</span>
</p>
<p class="MsoNormal" style="margin: 0cm 1.25pt 0pt 0cm; text-indent: 0.1pt;"></p>
<p class="MsoNormal" style="margin: 0cm 1.25pt 0pt 0cm; text-indent: 0.1pt;"></p>
<p class="MsoNormal" style="margin: 0cm 1.25pt 0pt 0cm; text-indent: 0.1pt;"></p>
<p class="MsoNormal" style="margin: 0cm 1.25pt 0pt 0cm; text-indent: 0.1pt;"><span style="font-size: small;"></span>
</p>
<p class="MsoNormal" style="margin: 0cm 1.25pt 0pt 0cm; text-indent: 0.1pt;"><span style=""><span lang="EN-US"><span style="color: #008000;"><span style="font-size: small;">3.为事务建立回滚段</span>
</span>
</span>
</span>
</p>
<p class="MsoNormal" style="margin: 0cm 1.25pt 0pt 0cm; text-indent: 0.1pt;"><span style=""><span lang="EN-US"></span>
</span>
</p>
<p class="MsoNormal" style="margin: 0cm 1.25pt 0pt 0cm; text-indent: 0.1pt;"><span style=""></span>
</p>
<p class="MsoNormal" style="margin: 0cm 1.25pt 0pt 0cm; text-indent: 0.1pt;"></p>
<p class="MsoNormal" style="margin: 0cm 1.25pt 0pt 0cm; text-indent: 0.1pt;"><span style=""><span style="font-size: small;"><span style="font-size: small;">在完成本事务所有相关的<span lang="EN-US">redo log buffer</span>
之后,服务器进程开始改写这个<span lang="EN-US">db buffer</span>
的块头部事务列表并写入<span lang="EN-US">scn</span>
,然后<span lang="EN-US">copy</span>
包含这个块的头部事务列表及<span lang="EN-US">scn</span>
信息的数据副本放入回滚段中,将这时回滚段中的信息称为数据块的“前映像“,这个”前映像“用于以后的回滚、恢复和一致性读。(回滚段可以存储在专门的回滚表空间中,这个表空间由一个或多个物理文件组成,并专用于回滚表空间,回滚段也可在其它表空间中的数据文件中开辟。)</span>
</span>
</span>
</p>
<p class="MsoNormal" style="margin: 0cm 1.25pt 0pt 0cm; text-indent: 0.1pt;"><span style=""></span>
</p>
<p class="MsoNormal" style="margin: 0cm 1.25pt 0pt 0cm; text-indent: 0.1pt;"></p>
<p class="MsoNormal" style="margin: 0cm 1.25pt 0pt 0cm; text-indent: 0.1pt;"></p>
<p class="MsoNormal" style="margin: 0cm 1.25pt 0pt 0cm; text-indent: 0.1pt;"><span style=""><span style="font-size: small; color: #008000;"><span style="font-size: small;">4.本事务修改数据块</span>
</span>
</span>
</p>
<p class="MsoNormal" style="margin: 0cm 1.25pt 0pt 0cm; text-indent: 0.1pt;"><span style=""></span>
</p>
<p class="MsoNormal" style="margin: 0cm 1.25pt 0pt 0cm; text-indent: 0.1pt;"><span style=""></span>
</p>
<p class="MsoNormal" style="margin: 0cm 1.25pt 0pt 0cm; text-indent: 0.1pt;"></p>
<p class="MsoNormal" style="margin: 0cm 1.25pt 0pt 0cm; text-indent: 0.1pt;"></p>
<p class="MsoNormal" style="margin: 0cm 1.25pt 0pt 0cm; text-indent: 0.1pt;"><span style=""><span style="font-size: small;"><span style="font-size: small;">准备工作都已经做好了,现在可以改写<span lang="EN-US">db buffer</span>
块的数据内容了,并在块的头部写入回滚段的地址。</span>
</span>
</span>
</p>
<p class="MsoNormal" style="margin: 0cm 1.25pt 0pt 0cm; text-indent: 0.1pt;"><span style=""></span>
</p>
<p class="MsoNormal" style="margin: 0cm 1.25pt 0pt 0cm; text-indent: 0.1pt;"><span style="" lang="EN-US"><span style="font-size: small;"></span>
</span>
</p>
<p class="MsoNormal" style="margin: 0cm 1.25pt 0pt 0cm; text-indent: 0.1pt;"><span style="" lang="EN-US"><span style="font-size: x-small;"><span style="color: #008000;"><span style="font-size: small;">5. 放入<span lang="EN-US">dirty list</span>
</span>
</span>
</span>
</span>
</p>
<p class="MsoNormal" style="margin: 0cm 1.25pt 0pt 0cm; text-indent: 0.1pt;"><span style="" lang="EN-US"><span style="font-size: x-small;"><span style="color: #008000;"></span>
</span>
</span>
</p>
<p class="MsoNormal" style="margin: 0cm 1.25pt 0pt 0cm; text-indent: 0.1pt;"><span style="" lang="EN-US"><span style="font-size: x-small;"></span>
</span>
</p>
<p class="MsoNormal" style="margin: 0cm 1.25pt 0pt 0cm; text-indent: 0.1pt;"><span style="" lang="EN-US"></span>
</p>
<p class="MsoNormal" style="margin: 0cm 1.25pt 0pt 0cm; text-indent: 0.1pt;"><span style=""><span style="font-size: small;"><span style="font-size: small;">如果一个行数据多次<span lang="EN-US">update</span>
而未<span lang="EN-US">commit</span>
,则在回滚段中将会有多个“前映像“,除了第一个”前映像“含有<span lang="EN-US">scn</span>
信息外,其他每个“前映像“的头部都有<span lang="EN-US">scn</span>
信息和“前前映像”回滚段地址。一个<span lang="EN-US">update</span>
只对应一个<span lang="EN-US">scn</span>
,然后服务器进程将在<span lang="EN-US">dirty list</span>
中建立一条指向此<span lang="EN-US">db buffer</span>
块的指针(方便<span lang="EN-US">dbwr</span>
进程可以找到<span lang="EN-US">dirty list</span>
的<span lang="EN-US">db buffer</span>
数据块并写入数据文件中)。</span>
</span>
</span>
</p>
<p class="MsoNormal" style="margin: 0cm 1.25pt 0pt 0cm; text-indent: 0.1pt;"></p>
<p class="MsoNormal" style="margin: 0cm 1.25pt 0pt 0cm; text-indent: 0.1pt;"><span style=""><span style="font-size: small;"><span style="font-size: small;">接着服务器进程会从数据文件中继续读入第二个数据块,重复前一数据块的动作,<span style="color: green;">数据块的读入、记日志、建立回滚段、修改数据块、放入<span lang="EN-US">dirty list</span>
</span>
。当<span lang="EN-US">dirty queue</span>
的长度达到阀值(一般是<span lang="EN-US">25%</span>
),服务器进程将通知<span lang="EN-US">dbwr</span>
把脏数据写出,就是释放<span lang="EN-US">db buffer</span>
上的锁存器,腾出更多的<span lang="EN-US">free db buffer</span>
。前面一直都是在说明<span lang="EN-US">oracle</span>
一次读一个数据块,其实<span lang="EN-US">oracle</span>
可以一次读入多个数据块(<span lang="EN-US">db_file_multiblock_read_count</span>
来设置一次读入块的个数)</span>
</span>
</span>
</p>
<p class="MsoNormal" style="margin: 0cm 1.25pt 0pt 0cm; text-indent: 0.1pt;"><span style="" lang="EN-US"><span style="font-size: small;"></span>
</span>
</p>
<p class="MsoNormal" style="margin: 0cm 1.25pt 0pt 0cm; text-indent: 0.1pt;"></p>
<p class="MsoNormal" style="margin: 0cm 1.25pt 0pt 0cm; text-indent: 0.1pt;"><span style="" lang="EN-US"><span style="font-size: small;"><strong><span style="color: #008000;">说明:</span>
</strong>
</span>
</span>
</p>
<p class="MsoNormal" style="margin: 0cm 1.25pt 0pt 0cm; text-indent: 0.1pt;"></p>
<p class="MsoNormal" style="margin: 0cm 1.25pt 0pt 0cm; text-indent: 0.1pt;"></p>
<p class="MsoNormal" style="margin: 0cm 1.25pt 0pt 0cm; text-indent: 0.1pt;"></p>
<p class="MsoNormal" style="margin: 0cm 1.25pt 0pt 0cm; text-indent: 0.1pt;"><span style=""><span style="font-size: small;"><span style="font-size: small;">在预处理的数据已经缓存在<span lang="EN-US">db buffer</span>
或刚刚被从数据文件读入到<span lang="EN-US">db buffer</span>
中,就要根据<span lang="EN-US">sql</span>
语句的类型来决定接下来如何操作。</span>
</span>
</span>
</p>
<p class="MsoNormal" style="margin: 0cm 1.25pt 0pt 0cm; text-indent: 0.1pt;"><span style="" lang="EN-US"><span style="font-size: small;"></span>
</span>
</p>
<p class="MsoNormal" style=""><span style="font-size: small;"><span style="" lang="EN-US"><span>1>.<span style='font-weight: normal; line-height: normal; font-style: normal; font-family: "Times New Roman"; font-variant: normal;'></span>
</span>
</span>
<span style="">如果是<span lang="EN-US">select</span>
语句,则要查看<span lang="EN-US">db buffer</span>
块的头部是否有事务,如果有事务,则从回滚段中读取数据;如果没有事务,则比较<span lang="EN-US">select</span>
的<span lang="EN-US">scn</span>
和<span lang="EN-US">db buffer</span>
块头部的<span lang="EN-US">scn</span>
,如果前者小于后者,仍然要从回滚段中读取数据;如果前者大于后者,说明这是一非脏缓存,可以直接读取这个<span lang="EN-US">db buffer</span>
块的中内容。</span>
</span>
</p>
<p class="MsoNormal" style="margin: 0cm 1.25pt 0pt 0.1pt;"><span style="" lang="EN-US"><span style="font-size: small;"></span>
</span>
</p>
<p class="MsoNormal" style=""><span style="font-size: small;"><span style="" lang="EN-US"><span>2>.<span style='font-weight: normal; line-height: normal; font-style: normal; font-family: "Times New Roman"; font-variant: normal;'> </span>
</span>
</span>
<span style="">如果是<span lang="EN-US">DML</span>
操作,</span>
<span style="">则即使在<span lang="EN-US">db buffer</span>
中找到一个没有事务,而且<span lang="EN-US">SCN</span>
比自己小的非脏缓存数据块,服务器进程仍然要到表的头部对这条记录申请加锁,加锁成功才能进行后续动作,如果不成功,则要等待前面的进程解锁后才能进行动作(这个时候阻塞是<span lang="EN-US">tx</span>
锁阻塞)。</span>
</span>
</p>
<p class="MsoNormal" style=""></p>
<p class="MsoNormal" style=""></p>
<p class="MsoNormal" style=""></p>
<p class="MsoNormal" style=""></p>
<p class="MsoNormal" style=""></p>
<p class="MsoNormal" style="margin: 0cm 1.25pt 0pt 0cm;"></p>
<p class="MsoNormal" style="margin: 0cm 1.25pt 0pt 0cm;"></p>
<p class="MsoNormal" style="margin: 0cm 1.25pt 0pt 0cm;"><span style="" lang="EN-US"><span style="font-size: x-small;"><span style="color: #008000;"><span style="font-size: x-small;"><span style=""><span lang="EN-US"><span style="font-size: x-small;"><span style="color: green;"><span style=""><span lang="EN-US"><span style=""><span style="font-size: small; color: #008000;"><span style="font-size: x-small;"><span style="" lang="EN-US"><span style="font-size: x-small;"><span style="color: #008000;"><span lang="EN-US"><span style="font-size: small;">6.用户commit或rollback</span>
</span>
</span>
</span>
</span>
</span>
</span>
</span>
</span>
</span>
</span>
</span>
</span>
</span>
</span>
</span>
</span>
</span>
</p>
<p class="MsoNormal" style="margin: 0cm 1.25pt 0pt 0cm;"><span style="" lang="EN-US"><span style="font-size: x-small;"><span style="color: #008000;"><span style="font-size: x-small;"><span style=""><span lang="EN-US"><span style="font-size: x-small;"><span style="color: green;"><span style=""><span lang="EN-US"><span style=""><span style="font-size: small; color: #008000;"><span style="font-size: x-small;"></span>
</span>
</span>
</span>
</span>
</span>
</span>
</span>
</span>
</span>
</span>
<span style="font-size: small;"></span>
</span>
</span>
</p>
<p class="MsoNormal" style="margin: 0cm 1.25pt 0pt 0cm;"><span style="" lang="EN-US"><span style="font-size: small;"></span>
</span>
</p>
<p class="MsoNormal" style="margin: 0cm 1.25pt 0pt 0cm;"><span style=""><span style="font-size: small;"><span style="font-size: x-small;"><span style="color: #008000;"><span style="font-size: small;">到现在为止,数据已经在<span lang="EN-US">db buffer或数据文件</span>
中修改完成,但是否要<strong>永久</strong>
写到数文件中,要由用户来决定<span lang="EN-US">commit</span>
(保存更改到数据文件)和<span lang="EN-US">rollback</span>
(撤销数据的更改),下面来看看在<span lang="EN-US">commit</span>
和<span lang="EN-US">rollback</span>
时,<span lang="EN-US">oracle</span>
都在做什么。</span>
</span>
</span>
</span>
</span>
</p>
<p class="MsoNormal" style="margin: 0cm 1.25pt 0pt 0cm;"><span style=""><span style="font-size: small;"><span style="font-size: x-small;"></span>
</span>
</span>
</p>
<p class="MsoNormal" style="margin: 0cm 1.25pt 0pt 0cm;"><span style=""><span style="font-size: small;"><span style="font-size: x-small;"></span>
</span>
</span>
</p>
<p class="MsoNormal" style="margin: 0cm 1.25pt 0pt 0cm;"><span style=""><span style="font-size: small;"></span>
</span>
</p>
<p class="MsoNormal" style="margin: 0cm 1.25pt 0pt 0cm;"><span style=""><span style="font-size: small;"><span style="font-size: x-small;"></span>
</span>
</span>
</p>
<p class="MsoNormal" style="margin: 0cm 1.25pt 0pt 0cm;"></p>
<p class="MsoNormal" style="margin: 0cm 1.25pt 0pt 0cm;"></p>
<p class="MsoNormal" style="margin: 0cm 1.25pt 0pt 0cm;"><span style="" lang="EN-US"><span style="font-size: x-small;"><span style="color: #008000;"><strong><span style="font-size: small;">用户执行commit命令</span>
</strong>
</span>
</span>
</span>
</p>
<p class="MsoNormal" style="margin: 0cm 1.25pt 0pt 0cm;"><span style="" lang="EN-US"><span style="font-size: small;"></span>
</span>
</p>
<p class="MsoNormal" style="margin: 0cm 1.25pt 0pt 0cm;"><span style="font-size: small;"><span style="font-size: small;"><span style="">只有当<span lang="EN-US">sql</span>
语句所影响的所有行所在的最后一个块被读入<span lang="EN-US">db buffer</span>
并且重做信息被写入<span lang="EN-US">redo log buffer</span>
(仅指日志缓冲区,而不包括日志文件)之后,用户才可以发去<span lang="EN-US">commit</span>
命令,<span lang="EN-US">commit</span>
触发<span lang="EN-US">lgwr</span>
进程,但不强制立即<span lang="EN-US">dbwr</span>
来释放所有相应<span lang="EN-US">db buffer</span>
块的锁(也就是<span lang="EN-US">no-force-at-commit,</span>
即提交不强制写),也就是说有可能虽然已经<span lang="EN-US">commit</span>
了,但在随后的一段时间内<span lang="EN-US">dbwr</span>
还在写这条<span lang="EN-US">sql</span>
语句所涉及的数据块。表头部的行锁并不在<span lang="EN-US">commit</span>
之后立即释放,而是要等<span lang="EN-US">dbwr</span>
进程完成之后才释放,这就可能会出现</span>
<span style="">一个用户请求另一用户已经<span lang="EN-US">commit</span>
的资源不成功的现象。</span>
</span>
</span>
</p>
<p class="MsoNormal" style="margin: 0cm 1.25pt 0pt 0cm;"><span style="font-size: small;"></span>
</p>
<p class="MsoNormal" style="margin: 0cm 1.25pt 0pt 0cm;"></p>
<p class="MsoNormal" style="margin: 0cm 1.25pt 0pt 0cm;"></p>
<p class="MsoNormal" style="margin: 0cm 1.25pt 0pt 0cm;"><span style="font-size: small;"><span style="font-size: x-small;"><span style=""><strong><span style="font-size: small;">A .</span>
</strong>
</span>
</span>
</span>
</p>
<p class="MsoNormal" style="margin: 0cm 1.25pt 0pt 0cm;"><span style="font-size: small;"><span style="font-size: x-small;"><span style=""><span style="font-size: small;">从<span lang="EN-US">Commit</span>
和<span lang="EN-US">dbwr</span>
进程结束之间的时间很短,如果恰巧在<span lang="EN-US">commit</span>
之后,<span lang="EN-US">dbwr</span>
未结束之前断电,因为<span lang="EN-US">commit</span>
之后的数据已经属于 </span>
</span>
</span>
</span>
</p>
<p class="MsoNormal" style="margin: 0cm 1.25pt 0pt 0cm;"><span style="font-size: small;"><span style="font-size: x-small;"><span style=""><span style="font-size: small;">数据文件的内容,但这部分文件没有完全写入到数据文件中。所以需要前滚。由于<span lang="EN-US">commit</span>
已经触发<span lang="EN-US">lgwr</span>
,这些所有未来得及写入数据文件的更改会在实例重启后,由<span lang="EN-US">smon</span>
进程根据重做日志文件来前滚,完成之前<span lang="EN-US">commit</span>
未完成的工作(即把更改写入数据文件)。</span>
</span>
</span>
</span>
</p>
<p class="MsoNormal" style="margin: 0cm 1.25pt 0pt 0cm;"><span style="font-size: small;"><span style="font-size: x-small;"></span>
</span>
</p>
<p class="MsoNormal" style="margin: 0cm 1.25pt 0pt 0cm;"><span style="font-size: small;"></span>
</p>
<p class="MsoNormal" style="margin: 0cm 1.25pt 0pt 0cm;"></p>
<p class="MsoNormal" style="margin: 0cm 1.25pt 0pt 0cm;"><span style="font-size: small;"><span style="font-size: x-small;"><span style=""><strong><span style="font-size: small;">B.</span>
</strong>
</span>
</span>
</span>
</p>
<p class="MsoNormal" style="margin: 0cm 1.25pt 0pt 0cm;"><span style="font-size: small;"><span style="font-size: small;"><span style="">如果未<span lang="EN-US">commit</span>
就断电了,因为数据已经在<span lang="EN-US">db buffer</span>
更改了,没有<span lang="EN-US">commit</span>
,说明这部分数据不属于数据文件,由于<span lang="EN-US">dbwr</span>
之前触发<span lang="EN-US">lgwr</span>
(也就是只要数据更改,肯定要先有<span lang="EN-US">log</span>
),</span>
<span style="">所有<span lang="EN-US">DBWR</span>
在数据文件上的修改都会被先一步记入重做日志文件,实例重启后,<span lang="EN-US">SMON</span>
进程再根据重做日志文件来回滚。</span>
</span>
</span>
</p>
<p class="MsoNormal" style="margin: 0cm 1.25pt 0pt 0cm;"><span style="" lang="EN-US"><span style="font-size: small;"></span>
</span>
</p>
<p class="MsoNormal" style="margin: 0cm 1.25pt 0pt 0cm;"></p>
<p class="MsoNormal" style="margin: 0cm 1.25pt 0pt 0cm;"></p>
<p class="MsoNormal" style="margin: 0cm 1.25pt 0pt 0cm;"><span style=""><span style="font-size: small;"><span style="font-size: small;">其实<span lang="EN-US">smon</span>
的前滚回滚是根据<strong>检查点</strong>
来完成的,当一个全部检查点发生的时候,首先让<span lang="EN-US">LGWR</span>
进程将<span lang="EN-US">redo log buffer</span>
中的所有缓冲(<span style="color: #008000;">包含未提交的重做信息</span>
)写入重做日志文件,然后让<span lang="EN-US">dbwr</span>
进程将<span lang="EN-US">db buffer</span>
已提交的缓冲写入数据文件(<span style="color: #008000;">不强制写未提交的</span>
)。然后更新控制文件和数据文件头部的<span lang="EN-US">SCN</span>
,表明当前数据库是一致的,在相邻的两个检查点之间有很多事务,有提交和未提交的。像前面的前滚回滚比较完整的说法是如下的说明:</span>
</span>
</span>
</p>
<p class="MsoNormal" style="margin: 0cm 1.25pt 0pt 0cm;"><span style=""></span>
</p>
<p class="MsoNormal" style="margin: 0cm 1.25pt 0pt 0cm;"><span style=""></span>
</p>
<p class="MsoNormal" style="margin: 0cm 1.25pt 0pt 0cm;"></p>
<p class="MsoNormal" style="margin: 0cm 1.25pt 0pt 0cm;"></p>
<p class="MsoNormal" style="margin: 0cm 1.25pt 0pt 0cm;"><span style=""><span style="font-size: small;"><span style="font-size: x-small;"><strong><span style="font-size: small;">A.</span>
</strong>
</span>
</span>
</span>
</p>
<p class="MsoNormal" style="margin: 0cm 1.25pt 0pt 0cm;"><span style=""><span style="font-size: small;"><span style="font-size: small;">发生检查点之前断电,并且当时有一个未提交的改变正在进行,实例重启之后,<span lang="EN-US">SMON</span>
进程将从上一个检查点开始核对这个检查点之后记录在重做日志文件中已提交的和未提交改变,因为<span lang="EN-US">dbwr</span>
之前会触发<span lang="EN-US">lgwr</span>
,所以<span lang="EN-US">dbwr</span>
对数据文件的修改一定会被先记录在重做日志文件中。因此,断电前被<span lang="EN-US">DBWN</span>
写进数据文件的改变将通过重做日志文件中的记录进行还原,叫做回滚,</span>
</span>
</span>
</p>
<p class="MsoNormal" style="margin: 0cm 1.25pt 0pt 0cm;"><span style=""></span>
</p>
<p class="MsoNormal" style="margin: 0cm 1.25pt 0pt 0cm;"></p>
<p class="MsoNormal" style="margin: 0cm 1.25pt 0pt 0cm;"><span style=""><span style="font-size: small;"></span>
</span>
</p>
<p class="MsoNormal" style="margin: 0cm 1.25pt 0pt 0cm;"><span style="" lang="EN-US"><span style="font-size: small;"><strong>B.</strong>
</span>
</span>
</p>
<p class="MsoNormal" style="margin: 0cm 1.25pt 0pt 0cm;"><span style=""><span style="font-size: small;"><span style="font-size: small;">如果断电时有一个已提交,但<span lang="EN-US">dbwr</span>
动作还没有完全完成的改变存在,因为已经提交,提交会触发<span lang="EN-US">lgwr</span>
进程,所以不管<span lang="EN-US">dbwr</span>
动作是否已完成,该语句将要影响的行及其产生的结果一定已经记录在重做日志文件中了,则实例重启后,<span lang="EN-US">SMON</span>
进程根据重做日志文件进行前滚</span>
</span>
</span>
</p>
<p class="MsoNormal" style="margin: 0cm 1.25pt 0pt 0cm;"><span style="" lang="EN-US"><span style="font-size: small;"></span>
</span>
</p>
<p class="MsoNormal" style="margin: 0cm 1.25pt 0pt 0cm;"></p>
<p class="MsoNormal" style="margin: 0cm 1.25pt 0pt 0cm;"><span style=""><span style="font-size: small;"><span style="font-size: small;">实例失败后用于恢复的时间由两个检查点之间的间隔大小来决定,可以通个四个参数设置检查点执行的频率:</span>
</span>
</span>
</p>
<p class="MsoNormal" style="margin: 0cm 1.25pt 0pt 0cm;"><span style="font-size: small;"><span style="font-size: small;"><span style="" lang="EN-US">Log_checkpoint_interval:</span>
<span style="">决定两个检查点之间写入重做日志文件的系统物理块<span lang="EN-US">(redo blocks)</span>
的大小,默认值是<span lang="EN-US">0</span>
,无限制</span>
</span>
</span>
</p>
<p class="MsoNormal" style="margin: 0cm 1.25pt 0pt 0cm;"><span style="font-size: small;"><span style="font-size: small;"><span style="" lang="EN-US">log_checkpoint_timeout: </span>
<span style="">决定了两个检查点之间的时间长度(秒),默认值是<span lang="EN-US">1800s</span>
</span>
</span>
</span>
</p>
<p class="MsoNormal" style="margin: 0cm 1.25pt 0pt 0cm;"><span style="font-size: small;"><span style="font-size: small;"><span style="" lang="EN-US">fast_start_io_target</span>
<span style="">:决定了用于恢复时需要处理的块的多少,默认值是<span lang="EN-US">0</span>
,无限制</span>
</span>
</span>
</p>
<p class="MsoNormal" style="margin: 0cm 1.25pt 0pt 0cm;"><span style="font-size: small;"><span style="font-size: small;"><span style="" lang="EN-US">fast_start_mttr_target</span>
<span style="">:直接决定了用于恢复的时间的长短,默认值是<span lang="EN-US">0</span>
,无限制</span>
</span>
</span>
</p>
<p class="MsoNormal" style="margin: 0cm 1.25pt 0pt 0cm;"><span style="font-size: small;"><span style="font-size: x-small;"></span>
</span>
</p>
<p class="MsoNormal" style="margin: 0cm 1.25pt 0pt 0cm;"><span style="" lang="EN-US"><span style="font-size: small;"></span>
</span>
</p>
<p class="MsoNormal" style="margin: 0cm 1.25pt 0pt 0cm;"><span style=""><span style="font-size: small;"><span style="font-size: small;">(<span lang="EN-US">SMON</span>
进程执行的前滚和回滚与用户的回滚是不同的,<span lang="EN-US">SMON</span>
是根据重做日志文件进行前滚或回滚,而用户的回滚一定是根据回滚段的内容进行回滚的。在这里要说一下回滚段存储的数据,假如是<span lang="EN-US">delete</span>
操作,则回滚段将会记录整个行的数据,假如是<span lang="EN-US">update,</span>
则回滚段只记录被修改了的字段的变化前的数据(前映像),也就是没有被修改的字段是不会被记录的,假如是<span lang="EN-US">insert</span>
,则回滚段只记录插入记录的<span lang="EN-US">rowid</span>
。这样假如事务提交,那回滚段中简单标记该事务已经提交;假如是回退,则如果操作是<span lang="EN-US">delete,</span>
回退的时候把回滚段中数据重新写回数据块,操作如果是<span lang="EN-US">update</span>
,则把变化前数据修改回去,操作如果是<span lang="EN-US">insert</span>
,则根据记录的<span lang="EN-US">rowid </span>
把该记录删除。)</span>
</span>
</span>
</p>
<p class="MsoNormal" style="margin: 0cm 1.25pt 0pt 0cm;"><span style="" lang="EN-US"><span style="font-size: small;"></span>
</span>
</p>
<p class="MsoNormal" style="margin: 0cm 1.25pt 0pt 0cm;"><span style="" lang="EN-US"><span style="font-size: small;"></span>
</span>
</p>
<p class="MsoNormal" style="margin: 0cm 1.25pt 0pt 0cm;"><span style="" lang="EN-US"><span style="font-size: x-small;"><strong><span style="color: #008000;"><span style="font-size: small;">用户执行rollback</span>
</span>
</strong>
</span>
</span>
</p>
<p class="MsoNormal" style="margin: 0cm 1.25pt 0pt 0cm;"><span style="" lang="EN-US"><span style="font-size: x-small;"><strong></strong>
</span>
</span>
</p>
<p class="MsoNormal" style="margin: 0cm 1.25pt 0pt 0cm;"><span style="" lang="EN-US"><span style="font-size: x-small;"><strong></strong>
</span>
</span>
</p>
<p class="MsoNormal" style="margin: 0cm 1.25pt 0pt 0cm;"></p>
<p class="MsoNormal" style="margin: 0cm 1.25pt 0pt 0cm;"><span style=""><span style="font-size: small;"><span style="font-size: small;">如果用户<span lang="EN-US">rollback</span>
,则服务器进程会根据数据文件块和<span lang="EN-US">DB BUFFER</span>
中块的头部的事务列表和<span lang="EN-US">SCN</span>
以及回滚段地址找到回滚段中相应的修改前的副本,并且用这些原值来还原当前数据文件中已修改但未提交的改变。如果有多个<span lang="EN-US">“</span>
前映像<span lang="EN-US">”</span>
,服务器进程会在一个<span lang="EN-US">“</span>
前映像<span lang="EN-US">”</span>
的头部找到<span lang="EN-US">“</span>
前前映像<span lang="EN-US">”</span>
的回滚段地址,一直找到同一事务下的最早的一个<span lang="EN-US">“</span>
前映像<span lang="EN-US">”</span>
为止。一旦发出了<span lang="EN-US">COMMIT</span>
,用户就不能<span lang="EN-US"><span lang="EN-US">rollback</span>
</span>
,这使得<span lang="EN-US">COMMIT</span>
后<span lang="EN-US">DBWR</span>
进程还没有全部完成的后续动作得到了保障。</span>
</span>
</span>
</p>
<p class="MsoNormal" style="margin: 0cm 1.25pt 0pt 0cm;"><span style="" lang="EN-US"><span style="font-size: small;"></span>
</span>
</p>
<p class="MsoNormal" style="margin: 0cm 1.25pt 0pt 0cm;"></p>
<p class="MsoNormal" style="margin: 0cm 1.25pt 0pt 0cm;"><span style="font-size: small;"><span style="font-size: small;"><span style="">到现在为例一个事务已经结束了。</span>
</span>
</span>
</p>
<p class="MsoNormal" style="margin: 0cm 1.25pt 0pt 0cm; text-indent: 0.1pt;"><span style="" lang="EN-US"><span style="font-size: small;"></span>
</span>
</p>
<p class="MsoNormal" style="margin: 0cm 1.25pt 0pt 0cm; text-indent: 0.1pt;"><span style="" lang="EN-US"><span style="font-size: small;"></span>
</span>
</p>
<p class="MsoNormal" style="margin: 0cm 1.25pt 0pt 0cm; text-indent: 0.1pt;"><span lang="EN-US"><span style="font-size: small;"></span>
</span>
</p>
<p class="MsoNormal" style="margin: 0cm 1.25pt 0pt 0cm; text-indent: 0.1pt;"><span style=""><span style="font-size: small;">说明:</span>
</span>
</p>
<p class="MsoNormal" style="margin: 0cm 1.25pt 0pt 0cm; text-indent: 0.1pt;"><span style="font-size: small;"><span style="font-size: small;"><span lang="EN-US">TM</span>
<span style="">锁:符合</span>
<span lang="EN-US">lock</span>
<span style="">机制的,用于保护对象的定义不被修改</span>
</span>
</span>
</p>
<p class="MsoNormal" style=""><span style="font-size: small;"><span style="font-size: small;"><span lang="EN-US">TX</span>
<span style="">锁:这个锁代表一个事务,是行级锁,用数据块头、数据记录头的一些字段表示,也是符合</span>
<span lang="EN-US">lock</span>
<span style="">机制,有</span>
<span lang="EN-US">resource structure</span>
<span style="">、</span>
<span lang="EN-US">lock structure</span>
<span style="">、</span>
<span lang="EN-US">enqueue</span>
<span style="">算法。</span>
</span>
</span>
</p>
<p class="MsoNormal" style=""></p>
<p class="MsoNormal" style=""></p>
<p class="MsoNormal" style=""></p>
<p class="MsoNormal" style=""><span style="font-size: small;"><span style="font-size: x-small;"><span style=""><span style="font-size: small;">----end----</span>
</span>
</span>
</span>
</p>
<p class="MsoNormal" style=""></p>
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值