zoukankan      html  css  js  c++  java
  • oracle对大对象类型操作:blob,clob,nclob

    

    1.基本介绍

    Oracle和plsql都支持lob(large object) 类型,用来存储大数量数据,如图像文件,声音文件等。Oracle 9i realse2支持存储最大为4g的数据,oracle 10g realse1支持最大8到128万亿字节的数据存储,依赖于你的db的block size。

    在plsql中可以申明的lob类型的变量如下: 

    • BFILE        二进制文件,存储在数据库外的操作系统文件,只读的。把此文件当二进制处理。 
    • BLOB        二进制大对象。存储在数据库里的大对象,一般是图像声音等文件。 
    • CLOB        字符型大对象。一般存储大数量文本信息。存储单字节,固定宽度的数据。 
    • NCLOB        字节字符大对象。存储单字节大块,多字节固定宽度,多字节变宽度数据。

    Oracle将lob分类为两种:

    1. 存储在数据库里的,参与数据库的事务。BLOB,CLOB,NCCLOB。

    2. 存储在数据库外的BFILE,不参与数据库的事务,也就是不能rollback或commit等,它依赖于文件系统的数据完整性。
    LONG和LONG
    RAW这两种数据类型也是存储字符的,但是有系列的问题,不建议使用,这里也就不讨论了。 

    2.LOB的使用 

    本部分不讨论lob的所有细节,只讨论lob的基本原理和在plsql中的基本使用,为plsql开发使用lob提供一个基础性指导。 

    本部分使用的表是: 
    1. /**   
    2. table script   
    3. **/   
    4. CREATE TABLE waterfalls (   
    5.        falls_name VARCHAR2(80),--name   
    6.        falls_photo BLOB,--照片   
    7.        falls_directions CLOB,--文字   
    8.        falls_description NCLOB,--文字   
    9.        falls_web_page BFILE);--指向外部的html页面   
    10. /  
    这个表我们并不需要clob和nclob两个,只取一就可以,这里全部定义只是为了演示使用。

    1. 理解LOB的Locator

    表中的Lob类型的列中存储的只是存储指向数据库中实际存储lob数据的一个指针。 

    在plsql中申明了一个lob类型的变量,然后从数据库中查询一个lob类型的值分配给变量,也只是将指针复制给了它,那么这个变量也会指向数据库中实际存放lob数据的地方。如:
    1. --understanding lob locators   
    2.   DECLARE   
    3.        photo BLOB;   
    4.     BEGIN   
    5.        SELECT falls_photo   
    6.          INTO photo   
    7.          FROM waterfalls   
    8.         WHERE falls_name='Dryer Hose';   
    Lob工作原理图解 

           从上面的图可以看出,要处理lob数据,必须先获得lob locators。我们可以通过一个select语句获取,当赋值给lob变量的时候,它也获得同样的lob locators。我们在plsql中处理可以使用dbms_lob包,里面内置了很多过程和函数来读取和修改我们的lob数据。下面给出处理lob数据的一般方法。 

    1.        通过select语句获取一个lob locator。 

    2.        通过调用dbms_lob.open打开lob。 

    3.        调用dbms_lob.getchunksize获得最佳读写lob值。 

    4.        调用dbms_lob.getlength获取lob数据的字节值。 

    5.        调用dbms_lob.read获取lob数据。 

    6.        调用dbms_lob.close关闭lob。 

    2.Empty
    lob and Null lob

    Empty的意思是我们已经获取了一个lob
    locator,但是没有指向任何lob数据。Null是定义了一个变量,但是没有获得lob locator。对lob类型的处理和其他类型不一样。如下面的例子:
    1. /* null lob example*/  
    2. DECLARE  
    3.   directions CLOB; --定义了,但是没有分配值,为null   
    4. BEGIN  
    5.   IF directions IS NULL THEN  
    6.     dbms_output.put_line('directions is null');  
    7.   ELSE  
    8.     dbms_output.put_line('directions is not null');  
    9.   END IF;  
    10. END;  
    11. /  
    12. DECLARE  
    13.   directions CLOB; --定义一个,并且分配值   
    14. BEGIN  
    15.   --删除一行   
    16.   DELETE FROM waterfalls WHERE falls_name = 'Munising Falls';  
    17.   --插入一行通过使用 EMPTY_CLOB(  ) to 建立一个lob locator   
    18.   INSERT INTO waterfalls  
    19.     (falls_name, falls_directions)  
    20.   VALUES  
    21.     ('Munising Falls', empty_clob());  
    22.   --获得lob locator,上面插入的数据,因为我们插入的是一个empty_clob(),那么lob locator不指向任何数据,虽然给变量分配了只   
    23.   SELECT falls_directions  
    24.     INTO directions  
    25.     FROM waterfalls  
    26.    WHERE falls_name = 'Munising Falls';  
    27.   IF directions IS NULL THEN  
    28.     dbms_output.put_line('directions is NULL');  
    29.   ELSE  
    30.     dbms_output.put_line('directions is not NULL'); --打印此句   
    31.   END IF;  
    32.   dbms_output.put_line('Length = ' || dbms_lob.getlength(directions)); --结果为o   
    33. END;  
    注意: 
    1. 上面例子中的empty_clob()是oracle的内置函数,创建了一个lob locator。但是我们没有让它指向任何数据,所以是empty。而且通过select语句给变量directions分配了lob locator,所以不是null,但是length为0,故为empty。 
    2. 在基本类型中,我们判断一个变量是不是有数据,只要is null就可以了。但是在lob类型中我们从以上的例子看出来是不正确的。Lob首先必须判断is null看是否分配lob locator,如果分配了还需要进一步检查length是否为0,看是否是empty,所以完整的是下面这样:
    1. IF some_clob IS NULL THEN  
    2.     --如果is null为true表示未分配,肯定没有数据   
    3.   ELSIF dbms_lob.getlength(some_clob) = 0 THEN  
    4.     --分配了length为0,也没有数据   
    5.   ELSE  
    6.     --有数据   
    7.   END IF;  

    3.建立LOB

    在上面我们使用empty_clob()建立了一个空的clob,lob
    locator只是一个指针,真正的数据是存储在磁盘中或数据库文件中。我 们先建立一个空的clob,然后我们可以update来让变量真正指向有数据的lob。Empty_clob()可以用来处理clob和nclob。在oracle 8i中可以使用temporary lob达到同样的效果。



    4.
    向LOB里写入数据
    当获得一个有效的lob
    locator之后,就可以使用dbms_lob包的下列procedure向lob中写入数据。 


           DBMS_LOB.WRITE:允许自动写入数据到lob中。 

           DBMS_LOB.WRITEAPPEND:向lob的末尾写入数据。
    1. --write lob   
    2. DECLARE  
    3.   directions      CLOB;  
    4.   amount          BINARY_INTEGER;  
    5.   offset          INTEGER;  
    6.   first_direction VARCHAR2(100);  
    7.   more_directions VARCHAR2(500);  
    8. BEGIN  
    9.   --Delete any existing rows for 'Munising Falls' so that this   
    10.   --example can be executed multiple times   
    11.   DELETE FROM waterfalls WHERE falls_name = 'Munising Falls';  
    12.   --Insert a new row using EMPTY_CLOB(  ) to create a LOB locator   
    13.   INSERT INTO waterfalls  
    14.     (falls_name, falls_directions)  
    15.   VALUES  
    16.     ('Munising Falls', empty_clob());  
    17.   --Retrieve the LOB locator created by the previous INSERT statement   
    18.   SELECT falls_directions  
    19.     INTO directions  
    20.     FROM waterfalls  
    21.    WHERE falls_name = 'Munising Falls';  
    22.   --Open the LOB; not strictly necessary, but best to open/close LOBs.   
    23.   dbms_lob.open(directions, dbms_lob.lob_readwrite);  
    24.   --Use DBMS_LOB.WRITE to begin   
    25.   first_direction := 'Follow I-75 across the Mackinac Bridge.';  
    26.   amount          := length(first_direction); --number of characters to write   
    27.   offset          := 1; --begin writing to the first character of the CLOB   
    28.   dbms_lob.write(directions, amount, offset, first_direction);  
    29.   --Add some more directions using DBMS_LOB.WRITEAPPEND   
    30.   more_directions := ' Take US-2 west from St. Ignace to Blaney Park.' ||  
    31.                      ' Turn north on M-77 and drive to Seney.' ||  
    32.                      ' From Seney, take M-28 west to Munising.';  
    33.   dbms_lob.writeappend(directions,  
    34.                        length(more_directions),  
    35.                        more_directions);  
    36.   --Add yet more directions   
    37.   more_directions := ' In front of the paper mill, turn right on H-58.' ||  
    38.                      ' Follow H-58 to Washington Street. Veer left onto' ||  
    39.                      ' Washington Street. You''ll find the Munising' ||  
    40.                      ' Falls visitor center across from the hospital at' ||  
    41.                      ' the point where Washington Street becomes' ||  
    42.                      ' Sand Point Road.';  
    43.   dbms_lob.writeappend(directions,  
    44.                        length(more_directions),  
    45.                        more_directions);  
    46.   --Close the LOB, and we are done.   
    47.   dbms_lob.close(directions);  
    48. END;  
    在这个例子里,我们使用了write 和writeappend这两个过程来插入数据到lob中。因为开始的时候,我们插入了一个空的lob locator。要注意一点,我们最后使用了dbms_lob.close方法关闭lob。这是一个好的方法,特别是在处理oracle text的时候,任何oracle text domain和function-based indexes被update是在wirte和writeappend的时候调用的,而不是在close的时候被update的。        
    我们向lob中写入数据的时候,没有必要更新表中的列。因为它保存的只是一个locator,我们的变量也获得同样的locator,当我们写入数据去lob的时候,locator并没有改变。改变的只是locator指向的物理数据。 


    5.
    从lob中读取数据

    步骤:a.通过select查询获得lob locator初始化lob变量。2.调用dbms_lob.read过程读取lob数据。 
    下面是dbms_lob.read过程的定义,注意参数.  
     
    1. PROCEDURE READ(lob_loc IN BLOB, --初始化后的lob变量lob locator   
    2.                amount  IN OUT NOCOPY INTEGER--读取的数量(clob为字符数,blob,bfile是字节数)   
    3.                offset  IN INTEGER--开始读取位置   
    4.                buffer  OUT RAW); --读到的数据,raw要显示用转换函数,见bfile   
    5. PROCEDURE READ(lob_loc IN CLOB CHARACTER SET any_cs,  
    6.                amount  IN OUT NOCOPY INTEGER,  
    7.                offset  IN INTEGER,  
    8.                buffer  OUT VARCHAR2 CHARACTER SET lob_loc%charset);  
    9. PROCEDURE READ(file_loc IN BFILE,  
    10.                amount   IN OUT NOCOPY INTEGER,  
    11.                offset   IN INTEGER,  
    12.                buffer   OUT RAW);  

    1. --从lob中读取数据   
    2. DECLARE  
    3.   directions   CLOB;  
    4.   directions_1 VARCHAR2(300);  
    5.   directions_2 VARCHAR2(300);  
    6.   chars_read_1 BINARY_INTEGER;  
    7.   chars_read_2 BINARY_INTEGER;  
    8.   offset       INTEGER;  
    9. BEGIN  
    10.   --首先获得一个lob locator   
    11.   SELECT falls_directions  
    12.     INTO directions  
    13.     FROM waterfalls  
    14.    WHERE falls_name = 'Munising Falls';  
    15.   --记录开始读取位置   
    16.   offset := 1;  
    17.   --尝试读取229个字符,chars_read_1将被实际读取的字符数更新   
    18.   chars_read_1 := 229;  
    19.   dbms_lob.read(directions, chars_read_1, offset, directions_1);  
    20.   --当读取229个字符之后,更新offset,再读取225个字符   
    21.   IF chars_read_1 = 229 THEN  
    22.     offset       := offset + chars_read_1; --offset变为offset+chars_read_1,也就是从300开始   
    23.     chars_read_2 := 255;  
    24.     dbms_lob.read(directions, chars_read_2, offset, directions_2);  
    25.   ELSE  
    26.     chars_read_2 := 0; --否则后面不在读取   
    27.     directions_2 := '';  
    28.   END IF;  
    29.   --显示读取的字符数   
    30.   dbms_output.put_line('Characters read = ' ||  
    31.                        to_char(chars_read_1 + chars_read_2));  
    32.   --显示结果   
    33.   dbms_output.put_line(directions_1);  
    34.   dbms_output.put_line(length(directions_1));  
    35.   dbms_output.put_line(directions_2);  
    36.   dbms_output.put_line(length(directions_2));  
    37. END;  

    Dbms_lob.read的第2个参数是传递要读取的数量。对于clob是字符数,blob和bfile都是字节数。它是随着读取的数目自动更新的,offset不会更新。所以分布读取需要手动更新offset,下个offset是上一个offset+读取的数量。我们可以通过dbms_lob.get_length(lob_locator)获得这个lob的长度,结果clob是字符数,blob和bfile是字节数,然后分布读取。


  • 相关阅读:
    多测师讲解html _伪类选择器17_高级讲师肖sir
    多测师讲解html _后代选择器16_高级讲师肖sir
    多测师讲解html _组合选择器_高级讲师肖sir
    多测师讲解html _标签选择器14_高级讲师肖sir
    前端 HTML form表单标签 input标签 type属性 重置按钮 reset
    前端 HTML form表单标签 textarea标签 多行文本
    前端 HTML form表单标签 input标签 type属性 file 上传文件
    前端 HTML form表单标签 input标签 type属性 radio 单选框
    前端 HTML form表单标签 input标签 type属性 checkbox 多选框
    前端 HTML form表单目录
  • 原文地址:https://www.cnblogs.com/wanghang/p/6299341.html
Copyright © 2011-2022 走看看