文章詳情頁(yè)
Oracle使用ANYDATA列對(duì)數(shù)據(jù)串行化方法
瀏覽:3日期:2023-11-13 10:10:45
Oracle版本9提供了一種有趣的新的數(shù)據(jù)類型,開(kāi)發(fā)人員借助此類型可以聲明包括任何類型數(shù)據(jù)的變量。對(duì)于單個(gè)數(shù)據(jù)來(lái)說(shuō),此數(shù)據(jù)類型即ANYDATA。對(duì)于TABLE或者VARRAY數(shù)據(jù)來(lái)說(shuō),則為ANYDATASET。ANYTYPE用于描述存儲(chǔ)在ANYDATA或者ANYDATASET變量以及欄中的數(shù)據(jù)類型。這些數(shù)據(jù)類型對(duì)于處理存儲(chǔ)在數(shù)據(jù)庫(kù)中的XML數(shù)據(jù)或高級(jí)序列(Advanced Queues)具有非常重要的意義。說(shuō)明文檔中提到了ANYDATA數(shù)據(jù)類型可以用于對(duì)對(duì)象進(jìn)行串行化(serialize),但與之相關(guān)的示例較少。 串行化首先將數(shù)據(jù)值和其他結(jié)構(gòu)(strUCture)組成為另外一些結(jié)構(gòu),然后將生成的結(jié)構(gòu)的所有構(gòu)成成分輸出為流。流可以被結(jié)構(gòu)返回讀取,并且將覆蓋前一個(gè)會(huì)話的信息。通常而言,在應(yīng)用程序中進(jìn)行的保存和打開(kāi)文件的操作即不過(guò)是串行化的一種形式。 一個(gè)Oracle數(shù)據(jù)庫(kù)或許需要使用串行化功能來(lái)存儲(chǔ)一些表格數(shù)據(jù)的某個(gè)版本備份,這樣可以在不使用數(shù)據(jù)庫(kù)提交(commits)、回滾(rollbacks)、回閃(flashback)查詢的情況下對(duì)數(shù)據(jù)進(jìn)行查看和其他操作。許多應(yīng)用程序都會(huì)用到類似的對(duì)數(shù)據(jù)源的控制功能,諸如可以在應(yīng)用級(jí)對(duì)當(dāng)前和以前的數(shù)據(jù)版本進(jìn)行比較,或?qū)喜⒉僮鳎╩erge)和撤銷操作(undo)所產(chǎn)生數(shù)據(jù)改變進(jìn)行比較。很多此類應(yīng)用程序都被設(shè)計(jì)為對(duì)每個(gè)表格創(chuàng)建一個(gè)備份表格。而對(duì)于數(shù)據(jù)庫(kù)性能和開(kāi)發(fā)進(jìn)度來(lái)說(shuō),要維護(hù)這些眾多的備份表格以及之間的各種關(guān)系,成為了生產(chǎn)數(shù)據(jù)(production data)以外的沉重負(fù)擔(dān)。 而通過(guò)ANYDATA數(shù)據(jù)類型以及動(dòng)態(tài)SQL功能,使得通過(guò)單一的串行化存儲(chǔ)進(jìn)程來(lái)把許多需要備份的表格串行輸入到一個(gè)單獨(dú)的備份表格成為可能。ANYDATA的一個(gè)優(yōu)勢(shì)在于,不同于類似VARCHAR2的簡(jiǎn)單的轉(zhuǎn)換數(shù)據(jù)類型,使用ANYDATA方法原始的數(shù)據(jù)類型并不會(huì)丟失。數(shù)據(jù)可以被存儲(chǔ)在ANYDATA欄或者變量中而不會(huì)丟失任何細(xì)節(jié)(或根據(jù)在DATA和VARCHAR2之間進(jìn)行轉(zhuǎn)換的當(dāng)前NLS語(yǔ)義而定)。這些存儲(chǔ)的數(shù)據(jù)在轉(zhuǎn)化過(guò)程中不會(huì)有任何損失。 一個(gè)ANYDATA對(duì)象可以通過(guò)使用任何Convert*方法構(gòu)造簡(jiǎn)單值的方法來(lái)實(shí)現(xiàn),或者通過(guò)“piecewise”構(gòu)造方法創(chuàng)建諸如對(duì)象和數(shù)據(jù)庫(kù)一類的更為復(fù)雜的變量。對(duì)于本例而言,我將集中解釋如何使用Convert*方法。 為了創(chuàng)建一個(gè)串行化進(jìn)程,我使用了動(dòng)態(tài)SQL來(lái)產(chǎn)生一個(gè)對(duì)表格中所有數(shù)據(jù)的查詢命令,其中包括ROWID。然后我將查詢命令進(jìn)行分解并描述,從而得到一個(gè)關(guān)于欄和數(shù)據(jù)類型的列表。再定義提取(fetch)出欄,將每一欄從各行中提取出來(lái),然后將其插入到串行化表格中。在本例中我使用了DBMS_SQL,因?yàn)椤白陨韯?dòng)態(tài)SQL(native dynamic SQL)”現(xiàn)在還不能支持描述動(dòng)態(tài)查詢。絕大多數(shù)的工作都是對(duì)從DBMS_SQL數(shù)據(jù)類型代碼到合適的數(shù)據(jù)類型方法以及函數(shù)的轉(zhuǎn)換過(guò)程進(jìn)行處理。要得到這些代碼的列表,可以查看OCI包含文件ocidfn.h,或者是諸如USER_TAB_COLUMNS這樣的對(duì)查看(view)的定義。在本例中,我使用了簡(jiǎn)單的數(shù)據(jù)類型(可以在EMP和DEPT表格中找到),這樣可以直接對(duì)其進(jìn)行轉(zhuǎn)換。 drop table serialized_data;create table serialized_data(tablename varchar2(30) not null,row_id rowid not null,colseq integer not null,item anydata);create or replace procedure serialize(p_tablename varchar2)isl_tablename varchar2(30) := upper(p_tablename);c pls_integer;-- cursorx pls_integer;-- dummycol_cnt pls_integer;dtabdbms_sql.desc_tab;l_rowid char(18);l_anydata anydata;l_vc2 varchar2(32767);l_numbernumber;l_vcvarchar(32767);l_date date;l_raw raw(32767);l_chchar;l_clob clob;l_blob blob;l_bfile bfile;beginc := dbms_sql.open_cursor;dbms_sql.parse(c,'select rowid,'p_tablename'.* from 'p_tablename,dbms_sql.native);dbms_sql.describe_columns(c,col_cnt,dtab);dbms_sql.define_column(c,1,l_rowid,18);for i in 2 .. col_cnt loopcase dtab(i).col_typewhen 1 thendbms_sql.define_column(c,i,l_vc2,dtab(i).col_max_len);when 2 thendbms_sql.define_column(c,i,l_number);when 9 thendbms_sql.define_column(c,i,l_vc,dtab(i).col_max_len);when 12 thendbms_sql.define_column(c,i,l_date);when 23 thendbms_sql.define_column_raw(c,i,l_raw,dtab(i).col_max_len);when 96 thendbms_sql.define_column_char(c,i,l_ch,dtab(i).col_max_len);when 112 thendbms_sql.define_column(c,i,l_clob);when 113 thendbms_sql.define_column(c,i,l_blob);when 114 thendbms_sql.define_column(c,i,l_bfile);end case;end loop;x := dbms_sql.execute(c);while dbms_sql.fetch_rows(c) != 0 loopdbms_sql.column_value(c,1,l_rowid);for i in 2 .. col_cnt loopcase dtab(i).col_typewhen 1 thendbms_sql.column_value(c,i,l_vc2);l_anydata := ANYDATA.ConvertVarchar2(l_vc2);when 2 thendbms_sql.column_value(c,i,l_number);l_anydata := ANYDATA.ConvertNumber(l_number);when 9 thendbms_sql.column_value(c,i,l_vc);l_anydata := ANYDATA.ConvertVarchar(l_vc);when 12 thendbms_sql.column_value(c,i,l_date);l_anydata := ANYDATA.ConvertDate(l_date);when 23 thendbms_sql.column_value(c,i,l_raw);l_anydata := ANYDATA.ConvertRaw(l_raw);when 96 thendbms_sql.column_value(c,i,l_ch);l_anydata := ANYDATA.ConvertChar(l_ch);when 112 thendbms_sql.column_value(c,i,l_clob);l_anydata := ANYDATA.ConvertClob(l_clob);when 113 thendbms_sql.column_value(c,i,l_blob);l_anydata := ANYDATA.ConvertBlob(l_blob);when 114 thendbms_sql.column_value(c,i,l_bfile);l_anydata := ANYDATA.ConvertBFile(l_bfile);end case;insert into serialized_data (tablename,row_id,colseq,item)values (l_tablename,l_rowid,i,l_anydata);end loop;end loop;dbms_sql.close_cursor(c);end;/show errors; 假如我希望對(duì)“EMP”和“DEPT”表格串行化,我可以按照以下代碼通過(guò)SQL*Plus來(lái)完成: exec serialize('emp');exec serialize('dept');select t.item.gettypename() from serialized_data t; 使用ANYDATA中的一個(gè)問(wèn)題是,假如是對(duì)象,則只有很少的信息可以通過(guò)直接SQL恢復(fù)過(guò)來(lái)。表格數(shù)據(jù)必須使用PL/SQL過(guò)程進(jìn)行訪問(wèn)。
標(biāo)簽:
Oracle
數(shù)據(jù)庫(kù)
排行榜
