案例(1)
就假設我修改了一條資料:update people set name='Fusnow' where name='old fusnow';
那我需要做的事情包括:
在redo log buffer產生redo資訊(包括對錶的redo,undo的redo,索引什麼的就不考慮了)
在buffer cache裡修改name='Fusnow',修改undo segment
------------------
情況1
如果一切正常,我現在commit,commit會觸發lgwr把redo log buffer裡的資訊寫入到磁碟的redo log file,如果這個操作成功完成,那我的資料安全了,現在如果系統崩潰,儘管可能會丟失buffer cache裡的髒資料,但可以從redo log裡找到重做資訊,所以,可以恢複,當然這個情況不用rollback 。
------------------
情況2
如果lgwr把redo log buffer裡的資訊寫入到磁碟的redo log file的過程中系統就崩了,那實際上 對使用者而言commit沒有成功就報錯了,這時候datafile和redo log上都沒有我們要的資訊,所以正好 ,系統啟動的時候我這個改動的roll forward/back 都省了。
------------------
情況3
如果commit之前,有什麼原因導致我們要flush buffer cache,比如buffer cache滿了,oracle要 吧buffer cache裡的dirty data寫入到磁碟,這要觸發dbwr,但dbwr寫之前一定要觸發lgwr,先把 redo log buffer裡的資料寫入到redo log file。原因很簡單,如果不觸發lgwr,由於對於我的這個 改變的髒資料包括表的改動和undo改動,而dbwr很可能不是在一次io裡面把這些髒資料寫入磁碟,如 果就是這麼巧,我們先寫入了表的改動,還沒來得及寫undo的髒資料,資料庫崩了,那現在我們的狀 態是datafile裡面有改過的表資料,沒有undo資料,redo裡面沒有redo資訊,由於我是沒有commit, 所以要復原,但這種情況下是不可能的,因為undo丟了,可以重建undo的redo也丟了。因此, dbwr一定要觸發lgwr。
如果在dbwr觸發lgwr的前提下,我們先寫入了表的改動,還沒來得及寫undo的髒資料的時候資料庫 崩了,我們實際上是先roll forward,通過redo產生undo,再rollback,通過undo復原事務。
當然,有兄弟也提過了了,先後順序是1.roll forward, 2.open database, 3.rollback,我想這 主要是oracle為了節省時間,因為設計上按照1.roll forward, 2.rollback, 3.open database的順 序應該也是可以的,但這樣比較慢,我們完全可以在roll forward結束後馬上open database,然後讓 使用者訪問資料庫的其他部分,讓smon慢慢rollback,這時候如果使用者想訪問正被復原的資料是會被堵 塞的。當然,在fast模式下,oracle會優先rollback使用者想訪問的block,讓使用者儘快可以訪問這些正 被rollback的資料。
案例(2)
假定有一下動作陳述式:
update gaojf set name='exitgogo' where name='old_exitgogo';
這個語句是這樣執行的:
1:首先檢查name='old_exitgogo'是否記錄在buffer cache中,如果不在,讀取到buffer中。
2:在復原段資料表空間的相應復原段事務表中分配事務段,這個操作產生redo資訊。
3:從復原段中讀入或者在buffer中或者說是在buffer cache中建立name='old_exitgogo'的前鏡像 ,這個操作同樣產生redo資訊並記錄寫入redo buffer。
4:在資料緩衝區修改name='exitgogo',這個操作的日誌資訊也寫入redo buffer。
5:當使用者提交時刻,會在redo buffer中記錄提交資訊,同時會在復原段中標記該事務為非啟用狀 態(inactive),這點很重要。
可以看到,在一個事務進行過程中,redo和undo是交替出現的,redo buffer會首先記錄此事務變 化前的資料和變化後的資料,然後把變化前的資料寫入復原段,最後才在資料緩衝區中修改資料。