中国IT动力,最新最全的IT技术教程
最新100篇 | 推荐100篇 | 专题100篇 | 排行榜 | 搜索 | 在线API文档
首 页 | 程序开发 | 操作系统 | 软件应用 | 图形图象 | 网络应用 | 精文荟萃 | 教育认证 | 硬件维护 | 未整理篇 | 站长教程
ASP JS PHP工程 ASP.NET 网站建设 UML J2EESUN .NET VC VB VFP 网络维护 数据库 DB2 SQL2000 Oracle Mysql
服务器 Win2000 Office C DreamWeaver FireWorks Flash PhotoShop 上网宝典 CorelDraw 协议大全 网络安全 微软认证
硬件维护  CPU  主板  硬盘  内存  显卡  显示器  键盘鼠标  声卡音箱  打印机  机箱电源  BIOS  网卡  C#  Java  Delphi  vs.net2005
  当前位置:> 程序开发 > 编程语言 > Java > 数据库
关于oracle中大对象处理的一些方法和实例
作者:specialtopic 时间:2006-09-26 11:52 出处:CSDN 责编:月夜寒箫
              摘要:关于oracle中大对象处理的一些方法和实例

在oracle中,有4个大对象(lobs)类型可用,分别是blob,clob,bfile,nclob。    
  下面是对lob数据类型的简单介绍。    
  l   blob:二进制lob,为二进制数据,最长可达4GB,存贮在数据库中。    
  l   clob:字符lob,字符数据,最长可以达到4GB,存贮在数据库中。    
  l   bfile:二进制文件;存贮在数据库之外的只读型二进制数据,最大长度由操作系统限制。    
  l   nclob:支持对字节字符集合(nultibyte   characterset)的一个clob列。    
  对于如何检索和操作这些lob数据一直是oracle数据库开发者经常碰到的问题。下面我将在oracle对lob数据处理的一些方法和技巧,介绍给读者,希望能够对读者以后的开发有所帮助。    
  oracle中可以用多种方法来检索或操作lob数据。通常的处理方法是通过dbms_lob包。    
  其他的方法包括使用api(application   programming   interfaces)应用程序接口和oci(oracle   call   interface)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对象来传替表名!    
  example   1.    
  动态PL/SQL,对CLOB字段操作可传递表名table_name,表的唯一标志字段名field_id,clob字段名field_name记录号v_id,开始处理字符的位置v_pos,传入的字符串变量v_clob      
  修改CLOB的PL/SQL过程:updateclob      
  create   or   replace   procedure   updateclob(    
  table_name   in   varchar2,    
  field_id   in   varchar2,      
  field_name   in   varchar2,    
  v_id   in   number,    
  v_pos   in   number,    
  v_clob   in   varchar2)    
  is    
  lobloc   clob;    
  c_clob   varchar2(32767);    
  amt   binary_integer;    
  pos   binary_integer;    
  query_str   varchar2(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||'=   :id   for   update   ';    
  --initialize   buffer   with   data   to   be   inserted   or   updated    
  EXECUTE   IMMEDIATE   query_str   INTO   lobloc   USING   v_id;    
  --from   pos   position,   write   32766   varchar2   into   lobloc    
  dbms_lob.write(lobloc,   amt,   pos,   c_clob);    
  commit;    
  exception    
  when   others   then    
  rollback;    
  end;    
  l   /用法说明:      
  在插入或修改以前,先把其它字段插入或修改,CLOB字段设置为空empty_clob(),      
  然后调用以上的过程插入大于2048到32766个字符。      
  如果需要插入大于32767个字符,编一个循环即可解决问题。      
  查询CLOB的PL/SQL函数:getclob      
  create   or   replace   function   getclob(    
  table_name   in   varchar2,    
  field_id   in   varchar2,      
  field_name   in   varchar2,    
  v_id   in   number,    
  v_pos   in   number)   return   varchar2    
  is    
  lobloc   clob;    
  buffer   varchar2(32767);    
  amount   number   :=   2000;    
  offset   number   :=   1;    
  query_str   varchar2(1000);    
  begin    
  query_str   :='select   '||field_name||'   from   '||table_name||'   where   '||field_id||'=   :id   ';    
  --initialize   buffer   with   data   to   be   found    
  EXECUTE   IMMEDIATE   query_str   INTO   lobloc   USING   v_id;    
  offset:=offset+(v_pos-1)*2000;      
  --read   2000   varchar2   from   the   buffer    
  dbms_lob.read(lobloc,amount,offset,buffer);    
  return   buffer;    
  exception    
  when   no_data_found   then    
  return   buffer;    
  end;    
  l   用法说明:      
  用select   getclob(table_name,field_id,field_name,v_id,v_pos)   as   partstr   from   dual;      
  可以从CLOB字段中取2000个字符到partstr中,      
  编一个循环可以把partstr组合成dbms_lob.getlength(field_name)长度的目标字符串。      
  二、对于在其他不同的开发环境,例如vc,vb,pb,java等环境下对lob的处理,处理方法不尽相同,在这里将简要举几个例子来说明不在oracle开发环境下对lob的处理。    
  (一)   在pb中的处理    
  exampler   2.    
  string   ls_path,ls_filename,ls_jhdh      
  long   ll_num,ll_count,rtn      
  blob   ole_blob      
  ll_num=dw_lb.getrow()      
  if   ll_num>0   then   ls_jhdh=dw_lb.object.ct_njhdh[ll_num]      
  select   count(*)   into   :ll_count   from   sj_jh_jhfjb   where   ct_jhdlxbh='1'   and   ct_jhdh=:ls_jhdh   and   ct_jdlxbh=:is_jdlx;      
  if   ll_count>0   then      
  rtn=messagebox("提示","是否要修改此附件",question!,yesno!,1)      
  if   rtn=1   then      
  SELECTBLOB   ct_jhfjnr   INTO   le_blob   from   sj_jh_jhfjb   where   ct_jhdlxbh='1'   and   ct_jhdh=:ls_jhdh   and   ct_jdlxbh=:is_jdlx;      
  ole_1.objectdata   =ole_blob      
  If   ole_1.activate(offsite!)   <>   0   Then      
  Messagebox("OLE   Activate","不能激活")      
  Return   -1      
  end   If      
  end   if      
  else      
  messagebox("提示","没有附件")      
  end   if      
  end   if    
  (二)在vb中的处理    
  在vb中处理大对象,一般可以用OO4O(oracle   objects   for   ole)来处理大对象。这里介绍一种不用0040处理大对象blob的方法。    
  下面这段程序可以将一个文件(文本文件,doc文件,图象文件等)保存到数据库中,并可以将其从数据库读出      
  需要两个commandbutton      
  cmd1   名称   cmdsave   caption   保存      
  cmd2   名称   cmdread   caption   读取      
  一个cmddialog控件      
  同时需要创建一张表t_demo(字段id   类型   number,;字段text   类型   blob;)    
  exmple   3.    
  Option   Explicit    
  Dim   rn   As   ADODB.Connection    
  Public   Function   CreateDataSource(DataSource   As   String,   UserID   As   String,   Password   As   String)   As   Boolean    
  On   Error   GoTo   DbConErr:    
  Set   rn   =   New   ADODB.Connection    
  With   rn    
  .ConnectionString   =   "Provider=OraOledb.Oracle.1;"   &   _    
  "password="   &   Password   &   ";"   &   _    
  "User   ID   ="   &   UserID   &   ";"   &   _    
  "Data   Source="   &   DataSource   &   ";"   &   _    
  "Locale   Identifier=2052"    
  .Open    
  End   With    
  CreateDataSource   =   True    
  Exit   Function    
  DbConErr:    
  CreateDataSource   =   False    
  End   Function    
   
  Private   Sub   cmdRead_Click()    
  Dim   rs   As   New   ADODB.Recordset    
  rs.ActiveConnection   =   rn    
  rs.LockType   =   adLockOptimistic    
  rs.CursorLocation   =   adUseClient    
  rs.Source   =   "select   *   from   t_demo"    
  rs.Open    
  ComDlgDir.DialogTitle   =   "保存文件"    
  ComDlgDir.Filter   =   "*.*"    
  ComDlgDir.ShowSave    
  Call   BlobToFile(rs.Fields("text"),   ComDlgDir.filename)    
  Set   rs   =   Nothing    
  Exit   Sub    
  Set   rs   =   Nothing    
  End   Sub    
   
  Private   Sub   cmdsave_Click()    
  Dim   rs   As   New   ADODB.Recordset    
  rs.ActiveConnection   =   rn    
  rs.LockType   =   adLockOptimistic    
  rs.CursorLocation   =   adUseClient    
  rs.Source   =   "select   *   from   t_demo"    
  rs.Open    
  rs.AddNew      
  ComDlgDir.DialogTitle   =   "选取文件"    
  ComDlgDir.ShowOpen      
  rs.Fields("id").Value   =   1    
  If   ComDlgDir.filename   <>   ""   Then    
  Call   FileToBlob(rs.Fields("text"),   ComDlgDir.filename)    
  rs.Update    
  End   If      
  Set   rs   =   Nothing    
  Exit   Sub    
  Set   rs   =   Nothing      
  End   Sub    
   
  Private   Sub   Form_Load()    
  If   Not   CreateDataSource("sid",   "systemp",   "manager")   Then    
  MsgBox   "Connection   failure!"    
  End   If    
  End   Sub    
   
  fld   As   ADODB.Field,   filename   As   String,   Optional   ChunkSize   As   Long   =   8192)    
  Dim   fnum   As   Integer,   bytesleft   As   Long,   bytes   As   Long    
  Dim   tmp()   As   Byte    
  If   (fld.Attributes   And   adFldLong)   =   0   Then    
  Err.Raise   1001,   ,   "field   doesn't   support   the   GetChunk   method."    
  End   If    
  If   Dir$(filename)   =   ""   Then   Err.Raise   53,   ,   "File   not   found"    
  fnum   =   FreeFile      
  Open   filename   For   Binary   As   fnum    
  bytesleft   =   LOF(fnum)    
  Do   While   bytesleft    
  bytes   =   bytesleft    
  If   bytes   >   ChunkSize   Then   bytes   =   ChunkSize    
  ReDim   tmp(1   To   bytes)   As   Byte    
  Get   fnum,   ,   tmp    
  fld.AppendChunk   tmp    
  bytesleft   =   bytesleft   -   bytes    
  Loop    
  Close   #fnum    
  End   Sub    
   
  Sub   BlobToFile(fld   As   ADODB.Field,   filename   As   String,   Optional   ChunkSize   As   Long   =   8192)    
  Dim   fnum   As   Integer,   bytesleft   As   Long,   bytes   As   Long    
  Dim   tmp()   As   Byte    
  If   (fld.Attributes   And   adFldLong)   =   0   Then    
  Err.Raise   1001,   ,   "field   doesn't   support   the   GetChunk   method."    
  End   If    
  If   Dir$(filename)   <>   ""   Then   Kill   filename    
  fnum   =   FreeFile    
  Open   filename   For   Binary   As   fnum    
  bytesleft   =   fld.ActualSize    
  Do   While   bytesleft    
  bytes   =   bytesleft    
  If   bytes   >   ChunkSize   Then   bytes   =   ChunkSize    
  tmp   =   fld.GetChunk(bytes)    
  Put   #fnum,   ,   tmp    
  bytesleft   =   bytesleft   -   bytes    
  Loop    
  Close   #fnum    
  End   Sub  

(三)用jdbc处理lob    
  exmple   4.    
  首先是Getting   BLOB   and   CLOB   Locators   from   a   Result   Set    
  //   Select   LOB   locator   into   standard   result   set.    
  ResultSet   rs   =stmt.executeQuery   ("SELECT   blob_col,   clob_col   FROM   lob_table");    
  while   (rs.next())    
  {//   Get   LOB   locators   into   Java   wrapper   classes.    
  oracle.jdbc2.Blob   blob   =   (oracle.jdbc2.Blob)rs.getObject(1);    
  oracle.jdbc2.Clob   clob   =   (oracle.jdbc2.Clob)rs.getObject(2);    
  [...process...]    
  }    
  然后是Read   BLOB   data   from   BLOB   locator.    
  InputStream   byte_stream   =   my_blob.getBinaryStream();    
  byte   []   byte_array   =   new   byte   [10];    
  int   bytes_read   =   byte_stream.read(byte_array);    
  和Writing   BLOB   Data      
  java.io.OutputStream   outstream;    
  //   read   data   into   a   byte   array      
  byte[]   data   =   {0,   1,   2,   3,   4,   5,   6,   7,   8,   9};    
  //   write   the   array   of   binary   data   to   a   BLOB    
  outstream   =   ((BLOB)my_blob).getBinaryOutputStream();    
  outstream.write(data);    
  还有Passing   a   BLOB   Locator   to   a   Prepared   Statement    
  OraclePreparedStatement   ops   =   (OraclePreparedStatement)conn.prepareStatement    
  "INSERT   INTO   blob_table   VALUES(?)");      
  ops.setBLOB(1,   my_blob);    
  ops.execute();    
  最后应该注意:    
  insert的时候一定要用empty_blob()初始化    
  stmt.execute   ("insert   into   my_blob_table   values   ('row1',   empty_blob()");    
   
  (四)在pro*c中的处理    
  PRO*C可以用三种方式对LOB字段处理。      
  1、The   DBMS_LOB   package   inside   PL/SQL   blocks.      
  2、OCI   (Oracle   Call   Interface)   function   calls.      
  3、Embedded   SQL   statements.      
  Embedded   SQL   statements.的方式简单而且比较灵活。OTN上提供一个例子:      
  In   this   example   we   will   be   reading   data   from   a   BLOB   with   an   unknown   arbitrary   length   into   a   buffer   and   then   writing   the   data   from   the   buffer   into   an   external   file.      
  Our   buffer   is   small,   so   depending   on   the   size   of   the   BLOB   we   are   reading,   we   may      
  be   able   to   read   the   BLOB   value   into   the   buffer   in   a   single   READ   statement   or   we      
  may   be   required   to   utilize   a   standard   polling   method   instead.      
  First   we   start   off   with   oci.h   and   some   simple   local   variable   declarations      
  example   5.    
  #include        
  OCIBlobLocator   *blob   ;      
  FILE   *fp   ;      
  unsigned   int   amt,   offset   =   1   ;      
  Now   we   need   a   buffer   to   store   the   BLOB   value   and   then   write   to   the   file   from:      
  #define   MAXBUFLEN   5000      
  unsigned   char   buffer[MAXBUFLEN]   ;      
  EXEC   SQL   VAR   buffer   IS   RAW(MAXBUFLEN)   ;      
  Allocate   the   BLOB   host   variable   and   select   a   BLOB   which   we   will   READ:      
  EXEC   SQL   ALLOCATE   :blob   ;      
  EXEC   SQL   SELECT   a_blob   INTO   :blob   FROM   lob_table   WHERE   ...   ;      
  We   can   then   open   the   external   file   to   which   we   will   write   the   BLOB   value:      
  fp   =   fopen((const   char   *)"image.gif",   (const   char   *)"w")   ;      
  If   the   buffer   can   hold   the   entire   LOB   value   in   a   single   READ   we   need   to   catch   the      
  NOT   FOUND   condition   to   signal   LOB   READ   termination:      
  EXEC   SQL   WHENEVER   NOT   FOUND   GOTO   end_of_lob   ;      
  Now   do   our   first   READ.We   set   the   amount   to   the   maximum   value   of   4   Gigabytes.   It      
  is   larger   than   our   buffer   so   if   the   LOB   doesn't   fit   we   will   READ   using   a   polling      
  mode:      
  amt   =   4294967295   ;      
  EXEC   SQL   LOB   READ   :amt   FROM   :blob   AT   ffset   INTO   :buffer   ;      
  If   we   get   here   then   it   means   that   the   buffer   was   not   large   enough   to   hold   the   entire      
  LOB   value,   so   we   must   write   what   we   have   using   binary   I/O   and   continue   reading:      
  (void)   fwrite((void   *)buffer,   (size_t)MAXBUFLEN,   (size_t)1,   fp)   ;      
  We   use   a   standard   polling   method   to   continue   reading   with   the   LOB   READ   inside      
  of   an   infinite   loop.   We   can   set   up   the   NOT   FOUND   condition   to   terminate   the   loop:      
  EXEC   SQL   WHENEVER   NOT   FOUND   DO   break   ;      
  while   (TRUE)      
  {      
  During   polling,   the   offset   is   not   used   so   we   can   omit   it   in   subsequent   LOB   READs.      
  We   need   the   amount,   however,   because   it   will   tell   us   how   much   was   READ   in   the      
  last   READ   invocation      
  EXEC   SQL   LOB   READ   :amt   FROM   :blob   INTO   :buffer   ;      
  (void)   fwrite((void   *)buffer,   (size_t)MAXBUFLEN,   (size_t)1,   fp)   ;      
  }      
  Here,   we   have   reached   the   end   of   the   LOB   value.   The   amount   holds   the   amount   of      
  the   last   piece   that   was   READ.   During   polling,   the   amount   for   each   interim   piece      
  was   set   to   MAXBUFLEN,   or   the   maximum   size   of   our   buffer:      
  end_of_lob:      
  (void)   fwrite((void   *)buffer,   (size_t)amt,   (size_t)1,   fp)   ;      
   
   
  (五)   在delphi中的处理    
  对于lob字段而言,个人认为其使用比long类型有很大的灵活性,而且lob字段可以保存各类的数据,可以保存图片,大量的文字,现就clob跟blob两种类型加以说明,其中blob保存图片信息,clob保存大量文字。    
  exmple   6.    
  Create   table   test_table    
  (c_no   number(1)   not   null,    
  c_blob   blob,    
  c_clob   clob,    
  constraint   pk_test_table   primary   key   (c_no));    
   
  unit   Unit1;    
   
  interface    
   
  uses    
  Windows,   Messages,   SysUtils,   Variants,   Classes,   Graphics,   Controls,   Forms,    
  Dialogs,   StdCtrls,   DBCtrls,   Grids,   DBGrids,   DB,   DBTables,   ExtDlgs;    
   
  type    
  TForm1   =   class(TForm)    
  Database1:   TDatabase;   //用于连接数据库    
  Table1:   TTable;   //获取表信息    
  DataSource1:   TDataSource;      
  DBGrid1:   TDBGrid;    
  DBMemo1:   TDBMemo;   //显示c_clob字段内容    
  DBImage1:   TDBImage;   //显示c_blob字段内容    
  Button1:   TButton;   //插入按钮    
  Button2:   TButton;   //保存按钮    
  Table1C_NO:   TFloatField;   //Tfiled    
  Table1C_BLOB:   TBlobField;    
  Table1C_CLOB:   TMemoField;    
  OpenPictureDialog1:   TOpenPictureDialog;   //从文件获取图片    
  OpenDialog1:   TOpenDialog;   //从文件获取文字    
  procedure   Button1Click(Sender:   TObject);    
  procedure   Button2Click(Sender:   TObject);    
  private    
  {   Private   declarations   }    
  public    
  {   Public   declarations   }    
  end;    
   
  var    
  Form1:   TForm1;    
   
  implementation    
   
  {$R   *.dfm}    
   
  procedure   TForm1.Button1Click(Sender:   TObject);    
  begin   //插入操作    
  with   Table1   do    
  begin    
  Insert;   //将表状态置为插入状态    
  if   OpenPictureDialog1.Execute   then   //获得图片信息    
  Table1C_BLOB.LoadFromFile(OpenPictureDialog1.FileName);    
  if   OpenDialog1.Execute   then   //获得文字信息    
  Table1C_CLOB.LoadFromFile(OpenDialog1.FileName);    
  end;    
  end;    
   
  procedure   TForm1.Button2Click(Sender:   TObject);    
  begin   //提交插入内容    
  try    
  Table1.Post;    
  except    
  Application.MessageBox('错误发生','警告',0);    
  end;    
  end;    
   
  end.    

关闭本页
 
首页 | 投资与合作 | 服务条款 | 隐私政策 | 收藏本站 | 设为首页 | 新用户注册 | 免责声明 | 使用帮助
Copyright ©2005-2008 chinaitpower.com All rights reserved. www.chinaitpower.com 版权所有