关于Oracle中大对象的一些处理方法和实例.docx
《关于Oracle中大对象的一些处理方法和实例.docx》由会员分享,可在线阅读,更多相关《关于Oracle中大对象的一些处理方法和实例.docx(19页珍藏版)》请在冰豆网上搜索。
关于Oracle中大对象的一些处理方法和实例
在oracle中,有4个大对象(lobs)类型可用,分别是blob,clob,bfile,nclob。
下面是对lob数据类型的简单介绍。
blob:
二进制lob,为二进制数据,最长可达4GB,存贮在数据库中。
clob:
字符lob,字符数据,最长可以达到4GB,存贮在数据库中。
bfile:
二进制文件;存贮在数据库之外的只读型二进制数据,最大长度由操作系统限制。
nclob:
支持对字节字符集合(nultibytecharacterset)的一个clob列。
对于如何检索和操作这些lob数据一直是oracle数据库开发者经常碰到的问题。
下面我将在oracle对lob数据处理的一些方法和技巧,介绍给读者,希望能够对读者以后的开发有所帮助。
oracle中可以用多种方法来检索或操作lob数据。
通常的处理方法是通过dbms_lob包。
其他的方法包括使用api(applicationprogramminginterfaces)应用程序接口和oci(oraclecallinterface)oracle调用接口程序。
一、在oracle开发环境中我们可以用dbms_lob包来处理!
dbms_lob包功能强大,简单应用。
既可以用来读取内部的lob对象,也可以用来处理bfile对象。
但处理两者之间,还有一点差别。
处理内部lob对象(blob,clob)时,可以进行读和写,但处理外部lob对象bfile时,只能进行读操作,写的操作可以用pl/sql处理。
另外用sql也可以处理lob,但要注意sql仅可以处理整个lob,不能操作lob的数据片。
在dbms_lob包中内建了read(),append,write(),erase(),copy(),getlength(),substr()等函数,可以很方便地操作lob对象。
这里不做深入讨论,读者可以参看相关的书籍。
对于pl/sql,下面介绍一种技巧,用动态的pl/sql语句处理clob对象来传替表名!
example1.
动态PL/SQL,对CLOB字段操作可传递表名table_name,表的唯一标志字段名field_id,clob字段名field_name记录号v_id,开始处理字符的位置v_pos,传入的字符串变量v_clob
修改CLOB的PL/SQL过程:
updateclob
createorreplaceprocedureupdateclob(
table_nameinvarchar2,
field_idinvarchar2,
field_nameinvarchar2,
v_idinnumber,
v_posinnumber,
v_clobinvarchar2)
is
loblocclob;
c_clobvarchar2(32767);
amtbinary_integer;
posbinary_integer;
query_strvarchar2(1000);
begin
pos:
=v_pos*32766+1;
amt:
=length(v_clob);
c_clob:
=v_clob;
query_str:
=''select''||field_name||''from''||table_name||''where''||field_id||''=:
idforupdate'';
--initializebufferwithdatatobeinsertedorupdated
EXECUTEIMMEDIATEquery_strINTOloblocUSINGv_id;
--fromposposition,write32766varchar2intolobloc
dbms_lob.write(lobloc,amt,pos,c_clob);
commit;
exception
whenothersthen
rollback;
end;
l/用法说明:
在插入或修改以前,先把其它字段插入或修改,CLOB字段设置为空empty_clob(),
然后调用以上的过程插入大于2048到32766个字符。
如果需要插入大于32767个字符,编一个循环即可解决问题。
查询CLOB的PL/SQL函数:
getclob
createorreplacefunctiongetclob(
table_nameinvarchar2,
field_idinvarchar2,
field_nameinvarchar2,
v_idinnumber,
v_posinnumber)returnvarchar2
is
loblocclob;
buffervarchar2(32767);
amountnumber:
=2000;
offsetnumber:
=1;
query_strvarchar2(1000);
begin
query_str:
=''select''||field_name||''from''||table_name||''where''||field_id||''=:
id'';
--initializebufferwithdatatobefound
EXECUTEIMMEDIATEquery_strINTOloblocUSINGv_id;
offset:
=offset+(v_pos-1)*2000;
--read2000varchar2fromthebuffer
dbms_lob.read(lobloc,amount,offset,buffer);
returnbuffer;
exception
whenno_data_foundthen
returnbuffer;
end;
l用法说明:
用selectgetclob(table_name,field_id,field_name,v_id,v_pos)aspartstrfromdual;
可以从CLOB字段中取2000个字符到partstr中,
编一个循环可以把partstr组合成dbms_lob.getlength(field_name)长度的目标字符串。
二、对于在其他不同的开发环境,例如vc,vb,pb,java等环境下对lob的处理,处理方法不尽相同,在这里将简要举几个例子来说明不在oracle开发环境下对lob的处理。
(一)在pb中的处理
exampler2.
stringls_path,ls_filename,ls_jhdh
longll_num,ll_count,rtn
blobole_blob
ll_num=dw_lb.getrow()
ifll_num>0thenls_jhdh=dw_lb.object.ct_njhdh[ll_num]
selectcount(*)into:
ll_countfromsj_jh_jhfjbwherect_jhdlxbh=''1''andct_jhdh=:
ls_jhdhandct_jdlxbh=:
is_jdlx;
ifll_count>0then
rtn=messagebox("提示","是否要修改此附件",question!
yesno!
1)
ifrtn=1then
SELECTBLOBct_jhfjnrINTOle_blobfromsj_jh_jhfjbwherect_jhdlxbh=''1''andct_jhdh=:
ls_jhdhandct_jdlxbh=:
is_jdlx;
ole_1.objectdata=ole_blob
Ifole_1.activate(offsite!
)<>0Then
Messagebox("OLEActivate","不能激活")
Return-1
endIf
endif
else
messagebox("提示","没有附件")
endif
endif
(二)在vb中的处理
在vb中处理大对象,一般可以用OO4O(oracleobjectsforole)来处理大对象。
这里介绍一种不用0040处理大对象blob的方法。
下面这段程序可以将一个文件(文本文件,doc文件,图象文件等)保存到数据库中,并可以将其从数据库读出
需要两个commandbutton
cmd1名称cmdsavecaption保存
cmd2名称cmdreadcaption读取
一个cmddialog控件
同时需要创建一张表t_demo(字段id类型number,;字段text类型blob;)
exmple3.
OptionExplicit
DimrnAsADODB.Connection
PublicFunctionCreateDataSource(DataSourceAsString,UserIDAsString,PasswordAsString)AsBoolean
OnErrorGoToDbConErr:
Setrn=NewADODB.Connection
Withrn
.ConnectionString="Provider=OraOledb.Oracle.1;"&_
"password="[$Password&"]"&_
"UserID="[$UserID&"]"&_
"DataSource="[$DataSource&"]"&_
"LocaleIdentifier=2052"
.Open
EndWith
CreateDataSource=True
ExitFunction
DbConErr:
CreateDataSource=False
EndFunction
PrivateSubcmdRead_Click()
DimrsAsNewADODB.Recordset
rs.ActiveConnection=rn
rs.LockType=adLockOptimistic
rs.CursorLocation=adUseClient
rs.Source="select*fromt_demo"
rs.Open
ComDlgDir.DialogTitle="保存文件"
ComDlgDir.Filter="*.*"
ComDlgDir.ShowSave
CallBlobToFile(rs.Fields("text"),ComDlgDir.filename)
Setrs=Nothing
ExitSub
Setrs=Nothing
EndSub
PrivateSubcmdsave_Click()
DimrsAsNewADODB.Recordset
rs.ActiveConnection=rn
rs.LockType=adLockOptimistic
rs.CursorLocation=adUseClient
rs.Source="select*fromt_demo"
rs.Open
rs.AddNew
ComDlgDir.DialogTitle="选取文件"
ComDlgDir.ShowOpen
rs.Fields("id").Value=1
IfComDlgDir.filename<>""Then
CallFileToBlob(rs.Fields("text"),ComDlgDir.filename)
rs.Update
EndIf
Setrs=Nothing
ExitSub
Setrs=Nothing
EndSub
PrivateSubForm_Load()
IfNotCreateDataSource("sid","systemp","manager")Then
MsgBox"Connectionfailure!
"
EndIf
EndSub
fldAsADODB.Field,filenameAsString,OptionalChunkSizeAsLong=8192)
DimfnumAsInteger,bytesleftAsLong,bytesAsLong
Dimtmp()AsByte
If(fld.AttributesAndadFldLong)=0Then
Err.Raise1001,,"fielddoesn''tsupporttheGetChunkmethod."
EndIf
IfDir$(filename)=""ThenErr.Raise53,,"Filenotfound"
fnum=FreeFile
OpenfilenameForBinaryAsfnum
bytesleft=LOF(fnum)
DoWhilebytesleft
bytes=bytesleft
Ifbytes>ChunkSizeThenbytes=ChunkSize
ReDimtmp(1Tobytes)AsByte
Getfnum,,tmp
fld.AppendChunktmp
bytesleft=bytesleft-bytes
Loop
Close#fnum
EndSub
SubBlobToFile(fldAsADODB.Field,filenameAsString,OptionalChunkSizeAsLong=8192)
DimfnumAsInteger,bytesleftAsLong,bytesAsLong
Dimtmp()AsByte
If(fld.AttributesAndadFldLong)=0Then
Err.Raise1001,,"fielddoesn''tsupporttheGetChunkmethod."
EndIf
IfDir$(filename)<>""ThenKillfilename
fnum=FreeFile
OpenfilenameForBinaryAsfnum
bytesleft=fld.ActualSize
DoWhilebytesleft
bytes=bytesleft
Ifbytes>ChunkSizeThenbytes=ChunkSize
tmp=fld.GetChunk(bytes)
Put#fnum,,tmp
bytesleft=bytesleft-bytes
Loop
Close#fnum
EndSub
(三)用jdbc处理lob
exmple4.
首先是GettingBLOBandCLOBLocatorsfromaResultSet
//SelectLOBlocatorintostandardresultset.
ResultSetrs=stmt.executeQuery("SELECTblob_col,clob_colFROMlob_table");
while(rs.next())
{//GetLOBlocatorsintoJavawrapperclasses.
oracle.jdbc2.Blobblob=(oracle.jdbc2.Blob)rs.getObject
(1);
oracle.jdbc2.Clobclob=(oracle.jdbc2.Clob)rs.getObject
(2);
[...process...]
}
然后是ReadBLOBdatafromBLOBlocator.
InputStreambyte_stream=my_blob.getBinaryStream();
byte[]byte_array=newbyte[10];
intbytes_read=byte_stream.read(byte_array);
和WritingBLOBData
java.io.OutputStreamoutstream;
//readdataintoabytearray
byte[]data={0,1,2,3,4,5,6,7,8,9};
//writethearrayofbinarydatatoaBLOB
outstream=((BLOmy_blob).getBinaryOutputStream();
outstream.write(data);
还有PassingaBLOBLocatortoaPreparedStatement
OraclePreparedStatementops=(OraclePreparedStatement)conn.prepareStatement
"INSERTINTOblob_tableVALUES(?
)");
ops.setBLOB(1,my_blob);
ops.execute();
最后应该注意:
insert的时候一定要用empty_blob()初始化
stmt.execute("insertintomy_blob_tablevalues(''row1'',empty_blob()");
(四)在pro*c中的处理
PRO*C可以用三种方式对LOB字段处理。
1、TheDBMS_LOBpackageinsidePL/SQLblocks.
2、OCI(OracleCallInterface)functioncalls.
3、EmbeddedSQLstatements.
EmbeddedSQLstatements.的方式简单而且比较灵活。
OTN上提供一个例子:
InthisexamplewewillbereadingdatafromaBLOBwithanunknownarbitrarylengthintoabufferandthenwritingthedatafromthebufferintoanexternalfile.
Ourbufferissmall,sodependingonthesizeoftheBLOBwearereading,wemay
beabletoreadtheBLOBvalueintothebufferinasingleREADstatementorwe
mayberequiredtoutilizeastandardpollingmethodinstead.
Firstwestartoffwithoci.handsomesimplelocalvariabledeclarations
example5.
#include
OCIBlobLocator*blob;
FILE*fp;
unsignedintamt,offset=1;
NowweneedabuffertostoretheBLOBvalueandthenwritetothefilefrom:
#defineMAXBUFLEN5000
unsignedcharbuffer[MAXBUFLEN];
EXECSQLVARbufferISRAW(MAXBUFLEN);
AllocatetheBLOBhostvariableandselectaBLOBwhichwewillREAD:
EXECSQLALLOCATE:
blob;
EXECSQLSELECTa_blobINTO:
blobFROMlob_tableWHERE...;
WecanthenopentheexternalfiletowhichwewillwritetheBLOBvalue:
fp=fopen((constchar*)"image.gif",(constcha