保持?jǐn)?shù)據(jù)一致性和完整性,是每一款成功商業(yè)數(shù)據(jù)庫軟件都必須要做到的基本要求。從故障中恢復(fù),保證ACID原則,保證事務(wù)完整性,一直是Oracle數(shù)據(jù)庫核心功能組成部分。本篇主要介紹Oracle實(shí)例意外終止(斷電或者強(qiáng)制關(guān)閉)之后,重新啟動(dòng)時(shí)發(fā)生的恢復(fù)過程,也可以稱作“前滾和回滾”。
網(wǎng)站制作、成都網(wǎng)站建設(shè)介紹好的網(wǎng)站是理念、設(shè)計(jì)和技術(shù)的結(jié)合。創(chuàng)新互聯(lián)建站擁有的網(wǎng)站設(shè)計(jì)理念、多方位的設(shè)計(jì)風(fēng)格、經(jīng)驗(yàn)豐富的設(shè)計(jì)團(tuán)隊(duì)。提供PC端+手機(jī)端網(wǎng)站建設(shè),用營(yíng)銷思維進(jìn)行網(wǎng)站設(shè)計(jì)、采用先進(jìn)技術(shù)開源代碼、注重用戶體驗(yàn)與SEO基礎(chǔ),將技術(shù)與創(chuàng)意整合到網(wǎng)站之中,以契合客戶的方式做到創(chuàng)意性的視覺化效果。
基礎(chǔ)知識(shí)說明
為了更明確的說明問題,筆者首先介紹一下本文涉及到的一些重要知識(shí)。
數(shù)據(jù)庫實(shí)例失敗
我們經(jīng)常說的數(shù)據(jù)庫服務(wù)器failure是有多層含義的。Oracle數(shù)據(jù)庫是一個(gè)由多進(jìn)程組件共同構(gòu)成的結(jié)構(gòu)體系。最重要的部分包括監(jiān)聽器、Oracle數(shù)據(jù)庫實(shí)例兩個(gè)部分,當(dāng)然還包括各類文件,更廣義的還有硬件和操作系統(tǒng)OS。不同部分的Failure現(xiàn)象和處理方法都有所不同。本文所闡述的過程是Oracle實(shí)例失敗后的自動(dòng)恢復(fù)過程。
在實(shí)例失敗的時(shí)候,往往是突然性的終止。此時(shí)Oracle數(shù)據(jù)庫可能在進(jìn)行一系列完成或者未完成的事務(wù)。實(shí)例失敗恢復(fù),就是要將這些狀態(tài)進(jìn)行還原,恢復(fù)到數(shù)據(jù)完整性的狀態(tài)。
寫日志(RedoLog)在先機(jī)制
Oracle數(shù)據(jù)庫是采用“日志在先”機(jī)制的。當(dāng)我們對(duì)數(shù)據(jù)庫數(shù)據(jù)進(jìn)行修改時(shí),并不是立即將修改寫入到文件中,而是寫入到共享內(nèi)存SGA空間中的BufferCache里。同時(shí),將修改的日志不斷的寫入到SGA中另一塊Log Buffer緩存中。有一個(gè)后臺(tái)進(jìn)程LGWR不斷的將LogBuffer緩存中的日志內(nèi)容寫入到online redo log文件中。
寫入LogBuffer緩存和LGWR寫入文件的過程是異步進(jìn)行的。那么LGWR會(huì)在哪些情況下將日志緩沖區(qū)(全部?jī)?nèi)容)轉(zhuǎn)儲(chǔ)到日志文件呢?如下:--參考OCA認(rèn)證考試指南(1Z0-052,P40)ü 用戶進(jìn)行直接的commit操作;
ü RedoBuffer數(shù)據(jù)超過1/3;
ü DBWn啟動(dòng),將BufferCache中的臟數(shù)據(jù)寫入到文件中;ü 距離上次LGWR寫入操作超過三秒(三秒超時(shí),DBWn每三秒鐘會(huì)對(duì)一些緩沖區(qū)清理一次,這個(gè)時(shí)候,剛好符合觸發(fā)LGWR的第三點(diǎn));而數(shù)據(jù)文件寫入進(jìn)程DBWn工作的觸發(fā)點(diǎn)(此處注意:DBWn會(huì)將高速緩沖區(qū)的臟緩沖區(qū),即臟數(shù)據(jù)塊寫入數(shù)據(jù)文件,而不是緩沖區(qū)里頭的全部?jī)?nèi)容---參考OCA認(rèn)證考試指南(1Z0-052,P38))。
因?yàn)榭紤]到磁盤I/O會(huì)降低性能,DBWn采用的是極懶算法執(zhí)行寫入。如果對(duì)于經(jīng)常變臟的緩沖區(qū),即這邊緩沖區(qū)處于十分忙碌的狀態(tài),那么DBWn不會(huì)將緩沖區(qū)寫入磁盤的。反而一段時(shí)間來,任何會(huì)話都未曾關(guān)注的一些緩沖區(qū),DBWn會(huì)將其寫入到磁盤。因此DBWn寫臟緩沖區(qū)比較平緩和低頻率。但如果出現(xiàn)檢查點(diǎn)的情況例外:DBWn會(huì)將所有臟緩沖區(qū)全部寫入磁盤。---參考OCA認(rèn)證考試指南(1Z0-052,P38中,P39)。
ü 當(dāng)BufferCache中沒有任何可用緩沖區(qū);ü 臟緩沖區(qū)過多;
ü 遇到三秒超時(shí)(DBWn每三秒鐘會(huì)對(duì)一些緩沖區(qū)清理一次)ü 遇到檢查點(diǎn)
綜合DBWn和LGWR工作的特點(diǎn),我們可以得到日志文件的幾個(gè)特點(diǎn):
首先,日志文件的寫入是很頻繁的。LGWR會(huì)不斷將日志信息從LogBuffer中寫入Online Redo Log;其次,在日志文件上,可以有三個(gè)類型的事務(wù)事件。
1、事務(wù)結(jié)束,已經(jīng)被commit,之后打過checkpoint檢查點(diǎn)。這種事務(wù)記錄在LogFile上,但是變化信息已經(jīng)被DBWn寫入進(jìn)數(shù)據(jù)文件;2、事務(wù)結(jié)束,已經(jīng)被commit,之后沒有打入checkpint檢查點(diǎn)。這種情況下,LogFile已經(jīng)寫入了日志項(xiàng)目,數(shù)據(jù)文件可能包括臟數(shù)據(jù),也可能沒有寫入臟數(shù)據(jù);3、事務(wù)未結(jié)束,沒有commit。這種時(shí)候,數(shù)據(jù)塊DirtyBlock上面是有事務(wù)槽信息,表示未結(jié)束事務(wù),是不會(huì)將數(shù)據(jù)寫入到數(shù)據(jù)文件中。但是,日志LogBuffer可能將部分未提交的DML操作項(xiàng)目寫入到Log File中;檢查點(diǎn)Checkpoint
檢查點(diǎn)Checkpoint是數(shù)據(jù)庫一致性檢查的一個(gè)標(biāo)記。簡(jiǎn)單的說,就是在這個(gè)點(diǎn)上,Oracle保證各個(gè)文件(數(shù)據(jù)、控制、日志等)是一致的。檢查點(diǎn)的作用就是在進(jìn)行實(shí)例恢復(fù)的時(shí)候,告訴SMON進(jìn)程,這個(gè)點(diǎn)之前的內(nèi)容不需要進(jìn)行恢復(fù)。
前滾和回滾介紹
“前滾和回滾”是Oracle數(shù)據(jù)庫實(shí)例發(fā)生意外崩潰,重新啟動(dòng)的時(shí)候,由SMON進(jìn)行的自動(dòng)恢復(fù)過程。下面通過模擬實(shí)例和講解介紹這個(gè)過程。
失敗前場(chǎng)景說明
日志中記錄過程如下:
1、事務(wù)A進(jìn)行之后,結(jié)束commit。之后系統(tǒng)進(jìn)行了一次checkpointA;2、Checkpoint之后,進(jìn)行事務(wù)B,結(jié)束commit;3、進(jìn)行事務(wù)C,C事務(wù)量較大,其中進(jìn)行了一定量的RedoLog文件寫入。之后系統(tǒng)斷電;--按照LGWR的工作機(jī)制,C事務(wù)量比較大,所以應(yīng)用程序?qū)⒃趲追种幻雰?nèi)的時(shí)間里生成足以填充1/3秒的重做內(nèi)容,因此這會(huì)觸發(fā)LGWR將日志緩沖區(qū)的內(nèi)容轉(zhuǎn)儲(chǔ)到日志文件,但始終得不到針對(duì)C事務(wù)的提交記錄,這是需要回滾的。
4、還有種可能,事務(wù)B和D,事務(wù)D所用的緩沖區(qū)處于高速緩沖區(qū)不活躍的位置,而且事務(wù)B已提交,但其所用的緩沖區(qū)處于高速緩沖區(qū)活躍的位置。因此DBWn會(huì)將D事務(wù)緩沖區(qū)數(shù)據(jù)寫入數(shù)據(jù)文件,而沒將B事務(wù)的數(shù)據(jù)寫入。此種情況需要回滾D事務(wù),保留B事務(wù)。---參考OCP認(rèn)證考試指南全冊(cè)(P358下半部分內(nèi)容).
1、系統(tǒng)啟動(dòng)過程,進(jìn)入實(shí)例恢復(fù)階段
當(dāng)實(shí)例意外中斷的時(shí)候,各類型文件,包括控制文件、數(shù)據(jù)文件和日志文件上,會(huì)存在不一致的問題。這種不一致主要體現(xiàn)在SCN值的差異上。
實(shí)例在啟動(dòng)的時(shí)候,經(jīng)過三階段(nomount、mount和open)。在open之前,會(huì)進(jìn)行這種不一致現(xiàn)象的檢查,如果出現(xiàn)不一致,要啟動(dòng)SMON進(jìn)程的恢復(fù)流程。
SMON是Oracle實(shí)例的一個(gè)后臺(tái)進(jìn)程,主要負(fù)責(zé)進(jìn)行系統(tǒng)監(jiān)控恢復(fù)。進(jìn)行恢復(fù)的依據(jù)主要是RedoLog記錄。
2、前滾進(jìn)程
SMON首先找到最后SCN記錄的Redo LogFile。尋找最后一個(gè)打入的Checkpoint。
順序找到CheckPointA之后,表示A之前的所有事務(wù)都是完全寫入到數(shù)據(jù)文件中,不存在不一致性問題?;謴?fù)過程從CheckpointA開始,Oracle開始依據(jù)重做日志Redo Log的系列條目,進(jìn)行推進(jìn)。
首先遇到了事務(wù)B信息,由于事務(wù)B已經(jīng)commit,所以事務(wù)B所有相關(guān)的Redo Log條目已經(jīng)全都寫入到Redo LogFile中。所以,按照日志繼續(xù)條目推進(jìn),完全可以重演replay,并且應(yīng)用apply事務(wù)B的全部過程。
這樣,事務(wù)B全部實(shí)現(xiàn),最終將通過DBWn完全寫入到數(shù)據(jù)文件中。所以,實(shí)例失敗之前提交commit的事務(wù)B,完全恢復(fù)。
進(jìn)入事務(wù)C的范疇,由于一部分事務(wù)C的RedoLog條目已經(jīng)進(jìn)入Redo LogFile中(根據(jù)LGWR和DBWn的工作機(jī)制,事務(wù)C有可能將部分?jǐn)?shù)據(jù)塊寫入日志文件和數(shù)據(jù)文件,但這時(shí)候C事務(wù)始終沒提交,這是比較嚴(yán)重的訛誤,所以需要回滾),所以在進(jìn)行前滾的時(shí)候,一定會(huì)replay到這部分的內(nèi)容。不過,這部分內(nèi)容中不可能出現(xiàn)commit的標(biāo)記。所以,前滾的結(jié)果一定是遇到實(shí)例突然中斷的那個(gè)時(shí)點(diǎn)。此時(shí)replay的結(jié)果是,事務(wù)C沒有提交。這樣結(jié)束了前滾過程,進(jìn)入回滾階段。
3、回滾過程(與普通的回滾一樣(當(dāng)事務(wù)執(zhí)行失敗后自動(dòng)回滾或者命令:ROLLBACK.)---參考OCP認(rèn)證考試指南全冊(cè))對(duì)事務(wù)C(針對(duì)DML的update,當(dāng)然其他同理),要進(jìn)行回滾過程,釋放所有相關(guān)資源。在前滾中,利用日志填充了的撤銷塊和表數(shù)據(jù)塊的值,然后在回滾的時(shí)候,會(huì)將撤銷塊的值復(fù)制回表數(shù)據(jù)塊中(因?yàn)榇耸聞?wù)沒提交記錄),以此來進(jìn)行SGA中BufferCache數(shù)據(jù)塊恢復(fù)。
4、說說恢復(fù)過程的損耗
很多時(shí)候,由于我們事務(wù)規(guī)模較大,當(dāng)出現(xiàn)實(shí)例崩潰的時(shí)候,重啟所需要的時(shí)間很多。有一種經(jīng)驗(yàn)說法是,事務(wù)有多長(zhǎng),前滾和回滾所消耗的時(shí)間有多長(zhǎng)×2。而且,如果不能完成SMON恢復(fù)過程,數(shù)據(jù)庫是不能算作正常的Open的。
SMON的恢復(fù)過程是Oracle強(qiáng)制進(jìn)行的一個(gè)過程,即使恢復(fù)中發(fā)生斷電或者其他中斷失敗事件。Oracle在下一次啟動(dòng)的時(shí)候,還是會(huì)繼續(xù)這個(gè)過程,只有耐心等待。
通過檢查一些內(nèi)部視圖(X$視圖),可以觀察到恢復(fù)進(jìn)程和速度,但是絲毫不能影響到最終恢復(fù)的過程。
這個(gè)過程雖然可以保證數(shù)據(jù)一致性,但是也帶來了系統(tǒng)不能啟動(dòng),影響生產(chǎn)環(huán)境的問題。我們可以通過兩個(gè)方式進(jìn)行緩解:
首先,我們?cè)谠O(shè)計(jì)開發(fā)系統(tǒng)時(shí),要保證事務(wù)規(guī)模的可控性,不要讓事務(wù)規(guī)模在技術(shù)層面上過大。避免一旦發(fā)生崩潰,大規(guī)模強(qiáng)制回滾的發(fā)生;其次,一旦出現(xiàn)了這個(gè)強(qiáng)制回滾,要注意對(duì)生產(chǎn)環(huán)境的影響??梢圆捎脗鋷靤tandby進(jìn)行頂替,讓主庫安靜的慢慢恢復(fù);
execute執(zhí)行后
可以回滾
commit提交后
不可以回滾
其實(shí)Oracle提交數(shù)據(jù)是分兩步操作的,第一步execute執(zhí)行,第二步commit提交。對(duì)應(yīng)的PL\SQL也是要先點(diǎn)execute執(zhí)行,執(zhí)行后再點(diǎn)commit提交。
但是
commit提交后
可以用閃回查詢恢復(fù)原來的數(shù)據(jù)
因?yàn)閛racle會(huì)將近期的數(shù)據(jù)保存到快照中
如:
SELECT
*
FROM
TABLE_1
AS
OF
TIMESTAMP
TO_TIMESTAMP('20080606
20:00:00','YYYYMMDD
HH24:MI:SS');
這里'20080606
20:00:00'就是你想恢復(fù)數(shù)據(jù)到哪個(gè)時(shí)間狀態(tài)
TABLE_1是數(shù)據(jù)庫的表名
這樣查詢到的數(shù)據(jù)就是執(zhí)行更新操作之前的數(shù)據(jù)
學(xué)習(xí)存儲(chǔ)過程中使用斷點(diǎn)回滾事務(wù)時(shí),發(fā)現(xiàn)目前網(wǎng)絡(luò)上存在一個(gè)問題,那就是使用斷點(diǎn)回滾后,都忘記了一個(gè)很重要的事情,提交事務(wù)。雖然使用了斷點(diǎn)回滾,但是斷點(diǎn)回滾不像rollBack或commit一樣結(jié)束當(dāng)前事務(wù),而使用斷點(diǎn)回滾只會(huì)回滾到聲明斷點(diǎn)的地方,之前的產(chǎn)生的事務(wù)仍需要提交的,如果不提交,事務(wù)一直在數(shù)據(jù)庫中緩存.
Demo:
procedure doSomeThing(p_number out number) as
begin
insert into t_test_user_mingming(id,loginname,password,realname,type)
values(se_test_user_mingming_id.nextval,'xiaoming','1234','小明',1);
p_number := 1;
savepoint ps;--- 設(shè)置斷點(diǎn) ps
insert into t_test_info_mingming(id,pal,type,create_time,note)
values(se_test_info_id.nextval,'我想買臺(tái)thinkPad 可以俺莫有錢',1,sysdate,'ceshi');
p_number := 2;
savepoint sp;----設(shè)置斷點(diǎn) sp
insert into t_test_agent(agent_id) values(1);---我這里此行會(huì)拋出異常 ORA-01400 可以替換為下句 手動(dòng)拋出一個(gè)異常
-----RAISE_APPLICATION_ERROR (-20004,'拋出的異常玩玩');
commit;
exception --捕獲異常
when others then
rollback to ps; ---- 如果產(chǎn)生異常,回滾到斷點(diǎn) ps
p_number :=0;
commit; --- 提交事務(wù)
end doSomeThing;
這里本人做了實(shí)驗(yàn),如果在異常中不加 commit 語句,使用PL/SQL測(cè)試時(shí),異常在緩存,t_test_user_mingming 表中沒有數(shù)據(jù)記錄。
存儲(chǔ)過程里的事務(wù)操作:
create or replace procedure pr_mypro2(p_a in varchar2,p_b in varchar2,p_count out number)
temp varchar2(1000); /*定義臨時(shí)變量*/
is
begin
select code into p_count from table1 where a=p_a; /*查詢并返回值*/
temp := p_count; /*將返回值賦給臨時(shí)變量*/
savepoint point1; /*保存點(diǎn)*/
insert into table2(a,b)values(temp,p_b); /*將臨時(shí)變量值添加到新表的字段*/
savepoint point2;
insert into
exception
when others then
rollback to savepoint point1; /*異常處理,保存點(diǎn)下面的操作都不會(huì)被執(zhí)行*/
return;
end;
保存點(diǎn)(SAVEPOINT)是事務(wù)處理過程中的一個(gè)標(biāo)志,與回滾命令(ROLLBACK)結(jié)合使用,主要的用途是允許用戶將某一段處理回滾而不必回滾整個(gè)事務(wù)。
如果定義了多個(gè)savepoint,當(dāng)指定回滾到某個(gè)savepoint時(shí),那么回滾操作將回滾這個(gè)savepoint后面的所有操作(即使后面可能標(biāo)記了N個(gè)savepoint)。
例如,在一段處理中定義了五個(gè)savepoint,從第三個(gè)savepoint回滾,后面的第四、第五個(gè)標(biāo)記的操作都將被回滾,如果不使用ROLLBACK TO savepoint_name而使用ROLLBACK,將會(huì)滾整個(gè)事務(wù)處理。
1、首先oracle已提交的數(shù)據(jù)是可以使用閃回功能來找回?cái)?shù)據(jù)的。
2、其次要先確定提交的數(shù)據(jù)的大體時(shí)間。
3、最后點(diǎn)擊閃回按鍵,選擇重新執(zhí)行,就可以選擇提交的數(shù)據(jù)信息進(jìn)行閃回了。