劉義華
[摘要] 從數(shù)據(jù)備份、恢復(fù)的靈活性出發(fā),解析Oracle數(shù)據(jù)庫表結(jié)構(gòu),給出了Windows環(huán)境下通過計算機VB語言對Oracle數(shù)據(jù)庫的備份及恢復(fù)的實現(xiàn)方法和開發(fā)實例。
[關(guān)鍵詞] Oracle 數(shù)據(jù)庫 備份 恢復(fù) 跨平臺 數(shù)據(jù)字典
Oracle數(shù)據(jù)庫在鐵路運輸收入現(xiàn)代化管理中發(fā)揮著重要的作用,它存儲著包括客運、貨運、雜費等各類票據(jù)的歷史數(shù)據(jù),擔(dān)負著客貨票據(jù)的審核工作。因此對數(shù)據(jù)庫的管理、備份,維護系統(tǒng)數(shù)據(jù)的安全就顯得格外重要。不僅如此,如何充分地利用數(shù)據(jù)庫的功能,在巨量的歷史數(shù)據(jù)中快速獲取我們所需數(shù)據(jù),也是數(shù)據(jù)庫管理的一項重要內(nèi)容。實際工作中常常需要將數(shù)據(jù)庫數(shù)據(jù)跨操作系統(tǒng)平臺地備份和恢復(fù),因此需要一種直觀、靈活的工具軟件,用于實現(xiàn)Oracle數(shù)據(jù)庫數(shù)據(jù)在不同的平臺上的備份與恢復(fù)、導(dǎo)出與導(dǎo)入。
1 傳統(tǒng)的備份和恢復(fù)方法
Oracle數(shù)據(jù)庫有三種標準的備份方法,它們分別是導(dǎo)出/導(dǎo)入(EXP/IMP)、熱備份和冷備份。導(dǎo)出備份是一種邏輯備份,冷備份和熱備份是物理備份。
1.1 導(dǎo)出/導(dǎo)入(Export/Import)
利用Export可將數(shù)據(jù)從數(shù)據(jù)庫中提取出來,利用Import則可將提取出來的數(shù)據(jù)送回到Oracle數(shù)據(jù)庫中去。Oracle支持三種方式類型的輸出,分別是:① 表方式(T方式),將指定表的數(shù)據(jù)導(dǎo)出。② 用戶方式(U方式),將指定用戶的所有對象及數(shù)據(jù)導(dǎo)出。③ 全庫方式(Full方式),將數(shù)據(jù)庫中的所有對象導(dǎo)出。
數(shù)據(jù)導(dǎo)入(Import)的過程是數(shù)據(jù)導(dǎo)出(Export)的逆過程,分別將數(shù)據(jù)文件導(dǎo)入數(shù)據(jù)庫和將數(shù)據(jù)庫數(shù)據(jù)導(dǎo)出到數(shù)據(jù)文件。這是一種常用的數(shù)據(jù)備份方法,但它最小的操作對象是表。而在實際工作中,經(jīng)常需要以表內(nèi)的某個字段(如時間字段)為條件進行操作,因此Export/Import方法就存在一定的局限性。
1.2 冷備份
冷備份發(fā)生在數(shù)據(jù)庫已經(jīng)正常關(guān)閉的情況下,當(dāng)正常關(guān)閉時會提供給我們一個完整的數(shù)據(jù)庫。冷備份是將關(guān)鍵性文件拷貝到另外的位置的一種方法。因為它是將數(shù)據(jù)庫文件完整地拷貝,因此需要占用大量的服務(wù)器資源。
1.3 熱備份
熱備份是在數(shù)據(jù)庫運行的情況下,采用archivelog mode方式備份數(shù)據(jù)庫的方法。
從以上對這三種方法的分析可以看出:操作都必須在服務(wù)器上執(zhí)行,而且都是行命令方式提交。因此操作者不僅要了解數(shù)據(jù)庫知識,還需熟知操作系統(tǒng)平臺的各種命令,而且所生成的備份文件都是操作系統(tǒng)平臺下的二進制數(shù)據(jù)文件。當(dāng)數(shù)據(jù)庫需要跨平臺備份或移動時,以上方法就不適用了。筆者在實際工作中就遇到了這種情況。目前收入管理的操作系統(tǒng)平臺是VMS操作系統(tǒng)加Oracle數(shù)據(jù)庫??拓浌芾淼母鞣N數(shù)據(jù)庫表空間都建立在這一個平臺上,服務(wù)器磁盤空間就顯得相對有限。而大量的歷史數(shù)據(jù)又是運輸收入分析的基礎(chǔ),因此必需將歷史數(shù)據(jù)移動到其他操作系統(tǒng)平臺上,如在Windows下建立Oracle數(shù)據(jù)庫。由于Windows不能識別VMS下的數(shù)據(jù)文件,上述方法自然無法做到數(shù)據(jù)庫表從VMS到Windows的移動。根據(jù)實際工作需要,筆者用計算機VB語言編制了一個工具軟件,在C/S(客戶端/服務(wù)器)模式下實現(xiàn)了一種簡捷的、跨平臺的數(shù)據(jù)庫數(shù)據(jù)備份與恢復(fù)的方法,操作的范圍大到表空間內(nèi)所有的表,小至按表的字段值為操作條件,同時備份數(shù)據(jù)不僅用于數(shù)據(jù)恢復(fù),還能夠直接被再利用,如被EXCEL讀取后再加工。下面筆者詳細闡述該軟件的設(shè)計原理及實現(xiàn)過程。
2 設(shè)計思路
2.1 備份
在C/S模式下運用Microsoft ActiveX數(shù)據(jù)對象(ADO)建立對Oracle數(shù)據(jù)庫的連接,通過用戶數(shù)據(jù)字典獲取表空間內(nèi)的所有表名、表的數(shù)據(jù)結(jié)構(gòu);建立一個能夠按需要在程序運行過程中動態(tài)創(chuàng)建查詢語句的模型,然后根據(jù)創(chuàng)建的查詢條件創(chuàng)建數(shù)據(jù)集對象,將表名、表結(jié)構(gòu)、查詢條件以及數(shù)據(jù)集的所有數(shù)據(jù)導(dǎo)出到客戶端。為了導(dǎo)出的數(shù)據(jù)能夠兼有備份以外更多的用途,筆者使用文本文件存儲備份數(shù)據(jù),字段間使用ASC碼中的TAB符間隔;
2.2 恢復(fù)
建立對Oracle數(shù)據(jù)庫的連接后,判斷表空間內(nèi)是否存在欲恢復(fù)的表。如果有,而且數(shù)據(jù)結(jié)構(gòu)與備份的數(shù)據(jù)結(jié)構(gòu)一致,說明是在原數(shù)據(jù)庫上恢復(fù)數(shù)據(jù),通過SQL命令將數(shù)據(jù)導(dǎo)入相應(yīng)的表內(nèi);如果沒有,就根據(jù)表結(jié)構(gòu)創(chuàng)建表,再將數(shù)據(jù)導(dǎo)入相應(yīng)的表內(nèi)。
由于是通過ADO連接數(shù)據(jù)庫,而且備份文件存儲于客戶端,因此數(shù)據(jù)的導(dǎo)入導(dǎo)出不受數(shù)據(jù)庫所在的操作系統(tǒng)平臺限制,能夠?qū)崿F(xiàn)數(shù)據(jù)庫數(shù)據(jù)跨平臺的移動。
3 實現(xiàn)原理
表空間是Oracle數(shù)據(jù)庫中最大的邏輯單位與存儲空間單位,數(shù)據(jù)庫系統(tǒng)通過表空間為數(shù)據(jù)庫對象分配空間。數(shù)據(jù)庫表是一系列二維數(shù)組的集合,用來代表和儲存數(shù)據(jù)對象之間的關(guān)系,可以直觀地理解為具有行、列的表格。表中每列代表不同的對象屬性、有不同的名稱,統(tǒng)稱為字段;表中每行則代表這組數(shù)據(jù)不同時段、狀況下的取值。數(shù)據(jù)庫采用數(shù)據(jù)字典的模式管理表空間。數(shù)據(jù)字典由一組特殊的表組成,以二維數(shù)組的形式記錄表空間的所有信息,如數(shù)據(jù)字典TABLESPACE_NAME記錄著表空間名及其類型,SYS.COL記錄著表空間內(nèi)所有表的數(shù)據(jù)結(jié)構(gòu)等等??傊?,數(shù)據(jù)庫通過數(shù)據(jù)字典以表的結(jié)構(gòu)形式來管理表以及其他數(shù)據(jù)庫信息。數(shù)據(jù)庫數(shù)據(jù)的導(dǎo)入導(dǎo)出不僅僅是對數(shù)據(jù)的操作,更重要的是獲取表的數(shù)據(jù)結(jié)構(gòu)。只有這樣,才能在其他操作系統(tǒng)上克隆表結(jié)構(gòu),進而備份數(shù)據(jù)。下面,筆者詳細闡述該軟件編制的各個環(huán)節(jié)。
3.1 連接數(shù)據(jù)庫
在C/S模式下采用ADO (Microsoft ActiveX Data Objects)來快速建立與數(shù)據(jù)庫的連接。ADO具有高度的靈活性,它可以使用相同的編程模式連接到不同的操作系統(tǒng)平臺下的Oracle數(shù)據(jù)庫,而不管操作系統(tǒng)平臺的特定特性,同時又具有較低的內(nèi)存占用率。 因此當(dāng)在需要跨平臺移動數(shù)據(jù)的情況下,備份數(shù)據(jù)時連接原數(shù)據(jù)庫,而當(dāng)需要移動恢復(fù)數(shù)據(jù)時就連接目標數(shù)據(jù)庫。實現(xiàn)連接數(shù)據(jù)庫具體代碼如下:
在工程菜單中引用Microsoft ActiveX Data Object 2. 5 Library
聲明ADO連接對象為工程級全局變量
Public cnn As ADODB.Connection
cnn.ConnectionString = "PROVIDER=MSDASQL; " _
+ "DRIVER={Microsoft ODBC for Oracle};" _
+ "SERVER=" +數(shù)據(jù)庫別名 + ";UID=" + 用戶名 + ";PWD=" + 口令
3.2 獲取表空間信息
在建立連接對象后,可以通過Exexute方法執(zhí)行SQL命令,獲取表空間信息。
SQL> SELECT TABLESPACE_NAME FROM USER_TABLES
從該語句的查詢結(jié)果可以看出,數(shù)據(jù)字典視圖USER_TABLES中存儲有所有表名(TABLE_NAME字段)及其所屬的表空間名(TABLESPACE_NAME字段)。記錄集(Recordset)對象是ADO操作數(shù)據(jù)最常用的對象。因此通過執(zhí)行上述SQL命令創(chuàng)建并打開記錄集,即可獲取所有表名及其所屬的表空間名。程序代碼如下:
Public cnn As ADODB.Connection‘聲明ADO連接對象
Public rds As ADODB.Recordset ‘聲明記錄集Recordset對象
cnn.Open
rds.Open "SELECT TABLE_NAME, TABLESPACE_ NAME FROM USER_TABLES", cnn, adOpenDynamic, adLockOptimistic
Do While rds.EOF = False
List1.AddItem Trim(rds.Fields("TABLE_NAME"))
rds.MoveNext
Loop
rds.Close
cnn.Close
3.3 獲取表數(shù)據(jù)結(jié)構(gòu)
數(shù)據(jù)字典視圖SYS.COL中存儲所有表的數(shù)據(jù)結(jié)構(gòu)。以下SQL命令檢索出表中字段的定義信息。
SQL> desc sys.col
名稱 是否為空? 類型
------------------ -------- ----
TNAME NOT NULL VARCHAR2(30) 表名
COLNO NOT NULL NUMBER 字段序號
CNAME NOT NULL VARCHAR2(30) 字段名
COLTYPE VARCHAR2(9) 字段類型
WIDTH NOT NULL NUMBER 字段寬度
SCALE NUMBER 小數(shù)點位數(shù)
PRECISION NUMBER 整數(shù)位數(shù)
NULLS VARCHAR2(19)
DEFAULTVAL LONG
同樣是通過創(chuàng)建記錄集,便可以獲取表的數(shù)據(jù)結(jié)構(gòu)。在實現(xiàn)數(shù)據(jù)移動時,能夠在新的數(shù)據(jù)庫表空間中克隆表的數(shù)據(jù)結(jié)構(gòu)。
3.4 建立條件設(shè)置模型
對數(shù)據(jù)庫的備份通常是以表為單位進行操作,但隨著日積月累,表中的記錄數(shù)將越來越大。以客票數(shù)據(jù)為例,路局每月客票的售票量就達560萬以上,一年僅這一項數(shù)據(jù)的保存記錄近7千萬條。如果仍以表為單位操作,不但會重復(fù)地浪費空間資源,備份或恢復(fù)的過程將很漫長,過程中受意外事件干擾而中斷的概率也很高。因此筆者設(shè)計了一套條件查詢的設(shè)置模型,引入SQL命令中的條件查詢功能,將備份/恢復(fù)的操作單位由表縮小到以表中任意一個字段值為條件的查詢范圍,實現(xiàn)大表分階段的備份/恢復(fù),既節(jié)省時間,又節(jié)省磁盤空間。如對客票數(shù)據(jù)表,就可以按時間字段為條件,以月為單位備份/恢復(fù)數(shù)據(jù)。條件設(shè)置模型就是在操作者和數(shù)據(jù)庫之間建立一個平臺,由操作者輸入或動態(tài)選擇生成帶條件的SQL查詢命令。當(dāng)然,如果沒有設(shè)置任何條件,那么程序?qū)⑸蔁o條件的SQL查詢命令,操作的范圍就是整個表。
條件設(shè)置模型包含以下三部分:
3.4.1數(shù)據(jù)庫列表
通過單項或多項選擇方式選中欲操作的表,并列于其中。
3.4.2 SQL命令手工編輯
對于具有相同數(shù)據(jù)結(jié)構(gòu)的一組表或都具有共同字段的一組表,在選中這一組表后直接在該編輯區(qū)手工輸入SQL的條件。如客票數(shù)據(jù)庫中每個表都有一個記錄日期的字段“RQ”,如果想備份2008年1月的數(shù)據(jù),就可以選中數(shù)據(jù)表后在編輯區(qū)輸入“RQ=200801”,那么條件設(shè)置模型就會將所選中的表加入該條件生成一組SQL命令。對于多條件的情況同樣適用,只是在兩個條件句之間加入“AND”或“OR”表示兩句是“并且”還是“或者”的邏輯關(guān)系。如上例改為備份南昌站2008年1月的數(shù)據(jù),就可以選中數(shù)據(jù)表后在編輯區(qū)輸入“ZM=南昌AND RQ=200801”(其中ZM是表示站名的字段名稱)。
3.4.3字段參數(shù)動態(tài)設(shè)置
這是一個與數(shù)據(jù)庫互動的過程,涉及這幾個區(qū):字段區(qū)、邏輯關(guān)系區(qū)、字段值區(qū)。全過程分以下步驟:(以備份2008年1月的數(shù)據(jù)為例)
① 在數(shù)據(jù)庫列表雙擊選中欲操作的表(如選擇表LCTJ),字段區(qū)列出該表的所有字段,等待選擇;
② 在字段區(qū)雙擊選中欲操作的字段(選擇字段RQ),邏輯關(guān)系區(qū)提供如=、>、>=、<、<=、LIKE等比較運算符;
③ 在邏輯關(guān)系區(qū)選中“=”,這時字段值區(qū)以列表的形式列出RQ字段在表內(nèi)不重復(fù)的值;
④ 選擇值(200801)
通過以上四個步驟便生成了一條標準的條件SQL語句(SELECT * FROM LCTJ WHERE RQ=200801)。如果是多條件的情況,只要重復(fù)步驟②、③、④即可實現(xiàn)。而步驟③是通過選中比較運算符時觸發(fā)一個事件來實現(xiàn)RQ字段在表內(nèi)不重復(fù)的值的列表。該事件對RQ字段冠以DISTINCT關(guān)鍵字進行查詢(SELECT DISTINCT RQ FROM LCTJ),就能從表中把RQ字段的所有不重復(fù)的數(shù)據(jù)讀出來,并賦予字段值區(qū)。
3.5 數(shù)據(jù)備份
數(shù)據(jù)備份包括備份三部分內(nèi)容:備份條件、表的數(shù)據(jù)結(jié)構(gòu)、數(shù)據(jù)。備份內(nèi)容以文本文件形式存儲,記錄內(nèi)數(shù)據(jù)之間以ASCII碼中的TAB符間隔。之所以采用這種存儲形式,是因為在實際工作中經(jīng)常需要數(shù)據(jù)庫中的某部分數(shù)據(jù)進行一些數(shù)據(jù)分析工作,并不是為了備份數(shù)據(jù)。而這種存儲形式的數(shù)據(jù)就能夠直接被諸如EXCEL之類的軟件所讀取進行數(shù)據(jù)再利用。
3.5.1記錄備份條件
將對表所設(shè)置的備份條件記錄下來,實際上就是保存下條件設(shè)置模型所生成的SQL語句。它不但記錄了表名及備份時的數(shù)據(jù)環(huán)境的信息,同時也是為數(shù)據(jù)恢復(fù)做準備。
3.5.2記錄表的數(shù)據(jù)結(jié)構(gòu)
首先通過對數(shù)據(jù)字典視圖SYS.COL的查詢結(jié)果,獲取表的每一個字段的名稱、數(shù)據(jù)類型以及字段長度;其次是通過對數(shù)據(jù)字典視圖USER_TABLES的查詢結(jié)果獲取表所屬的表空間名;最后將完整的數(shù)據(jù)結(jié)構(gòu)記錄在備份文件中。
3.5.3備份數(shù)據(jù)
備份數(shù)據(jù)是用條件設(shè)置模型所生成的SQL語句通過ADO打開數(shù)據(jù)記錄對象RecordSet,該對象所生成的記錄集就是符合SQL條件的所有要備份的數(shù)據(jù),然后使用該對象的各種方法將所有記錄按既定的格式保存到備份文件中。
以下是以備份南昌站2008年1月的數(shù)據(jù)為例的程序代碼:
Public cnn As ADODB.Connection
Public rds As ADODB.Recordset
cnn.Open
rds.Open “SELECT * FROM LCTJ WHERE RQ=200801 AND ZM=‘南昌”, cnn, adOpenDynamic, adLockOptimistic
Do While rds.EOF = False
For ii = 0 To rds.Fields.Count – 1 對每條記錄的所有字段進行循環(huán)取數(shù)
If (ii <> rds.Fields.Count - 1) Then
If (IsNull(rds.Fields(ii)) = True) Then 對字段數(shù)據(jù)為空的特別處理
Print #1, ""; Chr(9);
Else
Print #1, rds.Fields(ii); Chr(9);
End If
Else
If (IsNull(rds.Fields(ii)) = True) Then對字段數(shù)據(jù)為空的特別處理
Print #1, ""; Chr(9)
Else
Print #1, rds.Fields(ii); Chr(9)
End If
End If
Next ii
rds.MoveNext
Loop
cnn.Close
3.6 數(shù)據(jù)恢復(fù)
3.6.1判斷所連接的數(shù)據(jù)庫內(nèi)是否存在要恢復(fù)的表
如果是在原位上恢復(fù)數(shù)據(jù),表自然是存在的;但如果要在另外平臺上重新建立數(shù)據(jù)庫,那么就需要新建表。首先從備份文件中讀取表名,通過對數(shù)據(jù)字典視圖USER_TABLES
的TABLE_NAME字段的查詢判斷表是否存在。如果表不存在,那么從備份文件中讀取表的數(shù)據(jù)結(jié)構(gòu)后發(fā)送SQL的CREATE命令新建一個同名同結(jié)構(gòu)的表。
3.6.2清除表內(nèi)與備份條件相符的原有記錄
為了防止數(shù)據(jù)的重復(fù),保持數(shù)據(jù)的完整性和唯一性,在正式恢復(fù)數(shù)據(jù)之前從備份文件中讀取備份時的條件語句,刪除表內(nèi)與此條件相符的所有記錄。
3.6.3恢復(fù)數(shù)據(jù)
經(jīng)上述準備,就可以進行恢復(fù)數(shù)據(jù)的步驟了。只要逐一讀取數(shù)據(jù)記錄,通過辨別TAB分隔符獲取每個字段的數(shù)據(jù),并將其寫入表內(nèi),直至最終完整地將數(shù)據(jù)恢復(fù),結(jié)束了全過程。
4 結(jié)語
該軟件采用VB+數(shù)據(jù)庫ADO技術(shù),實現(xiàn)了Oracle數(shù)據(jù)跨操作系統(tǒng)平臺的數(shù)據(jù)備份與恢復(fù)的過程,特別是加入了SQL條件,使得備份與恢復(fù)的范圍更加靈活,同時備份數(shù)據(jù)兼顧再利用的功能,滿足了運輸收入信息化管理工作的實際需要。