DBMS_LOB

1LOB背景

在现在的系统开发中,需要存储的已不仅仅是简单的文字信息,也包括一些图片、音像资料或者超长的文本,这要求后台数据库具有存储这些数据的能力,Oracle通过提供LOB对象实现了该功能。

2LOB

在ORACLE数据库中,LOB大对象类型是用来存储大量的二进制和文本数据的一种数据类型(一个LOB字段可存储达4GB的数据)。目前LOB分为内部LOB和外部LOB。

2.1内部LOB

内部LOB将数据以字节流的形式存储在数据库的内部,因而内部LOB的许多操作都可以参与事务,也可以像处理普通数据一样对其进行备份和恢复操作。

Oracle支持的三种内部LOB为:BLOB(二进制数据)、CLOB(单字节字符数据)、NCLOB(多字节国家字符数据)。其中CLOB和NCLOB类型适用于存储超长的文本数据,BLOB类型适用于存储大量的二 进制数据,如图像、视频等。

2.2外部LOB

ORACLE仅支持一种外部LOB类型:BFILE类型。在数据库内,该类型仅存储数据在操作系统中的位置信息,而数据的实体 以外部文件的形式存在与操作系统的文件系统中。因而该类型所表示的数据时只读的,不参与事务。该类型可帮助用户管理大量的由外部程序访问的文件。

3LOB的使用

ORACLE提供了多种使用和维护LOB的方式,如使用PL/SQL中的DBMS_LOB包,调用OCI(Oracle Call Interface)、使用Proc*C/C++、使用JDBC等。其中最方便有效的是使用PLSQL调用的DBMS_LOB包。

在ORACLE中,存储在LOB中的数据称为LOB的值,如使用SELECT对某一LOB字段进行选择查询,则返回的不是LOB的值,而是该LOB字段的定位器(相当于定向LOB值的指针),DBMS_LOB包中提供的所有函数和过程都以LOB定位器作为参数。

3.1 DBMS_LOB过程

DBMS_LOB包中主要提供以下几个过程供用户对内部LOB字段进行维护:

APPEND:将源LOB中的内容加到目的LOB中。

CLOSE:关闭已经打开的LOB。

CREATETEMPORARY:在用户的临时表空间中,建立临时LOB。

FILECLOSE:关闭打开的BFILE定位符所指向的OS文件。

FILECLOSEALL:关闭当前会话已经打开的所有BFILE文件。

FILEEXISTS:确定file_loc对应的OS文件是否存在,1:存在。0:不存在。

FILEGETNAME:获取BFILE定位符所对应的目录别名和文件名。

FILEISOPEN:确定BFILE对应的OS文件是否打开。

FREETEMPORARY:释放在默认临时表空间中的临时LOB。

FILEOPEN:打开文件。

GETCHUNKSIZE:当建立包含CLOB/BLOB列的表时,通过指定CHUNK参数可以指定操纵LOB需要分配的字节数(数据库尺寸的整数倍)默认为数据块的尺寸。

COPY:从源LOB中复制数据到目的LOB。

ERASE:删除LOB中全部或部分内容。

TRIM:将LOB值减少到指定的长度。

WRITE:向LOB中写入数据。

INSTR:返回特定样式数据从LOB某偏移位置开始出现N次的具体位置。

IDOPEN:确定LOB是否打开,打开:1,未打开:0。

ISTEMPORARY:确定定位符是否为临时LOB。

LOADFROMFILE:将BFILE的部分或全部内容复制到目标LOB变量。

LOADBLOBFROMFILE:将BFILE数据装载到BLOB中,并且在装载后取得最新的偏移位置。

OPEN:打开LOB,open_mode(只读:dbms_lob.lob_readonly,写:dbms_lob.lob_readwrite)。

COMPARE:比较两个同种数据类型的LOB的部分或全部值是否相同。

GETLENGTH:获取LOB的长度。

READ:从LOB中读出数据。

SUBSTR:与字符处理函数SUBSTR使用方法一样。

WRITEAPPEND:将缓冲区数据写到LOB尾部。

3.2常用过程

3.2.1写入对象

PROCEDURE WRITE(lob_loc IN OUT BLOB,

amount IN BINARY_INTEGER,

offset IN INTEGER,

buffer IN RAW);

PROCEDURE WRITE(lob_loc IN OUT CLOB CHARACTER SET any_cs,

amount IN BINARY_INTEGER,

offset IN INTEGER,

buffer IN VARCHAR2 CHARACTER SET lob_loc%charset);

各参数的含义为:

lob_loc:要写入的LOB定位器。

amount:写入LOB中的字节数。

offset:指定开始操作的偏移量。

buffer:指定写操作的缓冲区。

实例: DECLARE

obloc CLOB;

buffer VARCHAR2(2000);

amount NUMBER := 20;

offset NUMBER := 1;

BEGIN

--初始化要写入的数据

buffer := 'This is a writing example';

amount := length(buffer);

SELECT document

INTO lobloc --获取定位器并锁定行

FROM view_sites_info

WHERE site_id = 100

FOR UPDATE;

dbms_lob.write(lobloc,

amount,

1,

buffer);

COMMIT;

END;

注意事项:

(1)在调用写过程前一定要使用SELECT语句检索到定位器且用FOR UPDATE子句锁定行,否则不能更新LOB。

(2)写过程从offset指定的位置开始,向LOB中写入长度为amount的数据,原LOB中在这个范围内的任何数据都将被覆盖。

(3)缓冲区的最大容量为32767字节,因此在写入大量数据时需多次调用该过程。

3.2.2读取对象

PROCEDURE WRITE(lob_loc IN OUT BLOB,

amount IN BINARY_INTEGER,

offset IN INTEGER,

buffer IN RAW);

PROCEDURE WRITE(lob_loc IN OUT CLOB CHARACTER SET any_cs,

amount IN BINARY_INTEGER,

offset IN INTEGER,

buffer IN VARCHAR2 CHARACTER SET lob_loc%charset);

参数的含义为:

lob_loc:要写入的LOB定位器。

amount:写入LOB中的字节数。

offset:指定开始操作的偏移量。

buffer:指定写操作的缓冲区。

实例:DECLARE

lobloc CLOB;

buffer VARCHAR2(2000);

amount NUMBER := 2;

offset NUMBER := 6;

BEGIN

SELECT document

INTO lobloc --获取定位器

FROM lob_store

WHERE lob_id = 100;

dbms_lob.read(lobloc,

amount,

offset,

buffer); --读取数据到缓冲区

dbms_output.put_line(buffer); --显示缓冲区中的数据

COMMIT;

END;

3.2.3复制对象

append存储过程用于将一个大对象添加到另一个大对象中,此时是将源大对象的内容全部添加过去

PROCEDURE append(dest_lob IN OUT NOCOPY BLOB,

src_lob IN BLOB);

PROCEDURE append(dest_lob IN OUT NOCOPY CLOB CHARACTER SET any_cs,

src_lob IN CLOB CHARACTER SET dest_lob%charset);

各个参数的含义如下:

dest_lob是被源lob添加到的目标lob的定位器。

src_lob是源lob的定位器。

any_cs用来指定字符集。

实例:VARCHAR类型的字符串最多只能存储32767个字符,超出这一长度后,将自动截取字符串到长度32767,导致部门输出内容丢失,甚至报错。

解决办法:可采用clob对象来保存

1.定义clob对象:l_table_rowspan_clob CLOB; --字符型的大对象

2.创建临时LOB: dbms_lob.createtemporary(l_table_rowspan_clob, TRUE);

3.将缓冲区数据写入到LOB中的特定位置:

l_table_line为报表输出字符串拼接对象,将l_table_line内容写入clob对象中

l_clob_lengnth := nvl(dbms_lob.getlength(l_table_rowspan_clob),0);--初始位置

dbms_lob.write(lob_loc => l_table_rowspan_clob, --是要操作的大型对象定位器

amount => length(l_table_line), --是要写到大型对象中去的字节数量

offset => l__clob_lengnth + 1, --是指定将数据写入到大型对象什么位置的偏移地址

buffer => l_table_line); --是写入到大型对象的数据缓冲区

l_clob_lengnth := nvl(dbms_lob.getlength(l_table_rowspan_clob),0);--最终位置

4.读取CLOD对象的内容

dbms_lob.read(lob_loc => l_table_rowspan_clob,

amount => l_r_amount,--要读取的字符数

offset => l_r_offset_start,--开始读取字符数的位置

buffer => l_r_buffer); --存储读取到数据的变量

DBMS_LOBDBMS_LOB

1   l_r_amount   := 16383;--定义每一次读取字符的数量
 2 
 3   l_clob_index := 0;
 4 
 5   LOOP
 6 
 7     l_clob_index := l_clob_index + 1;
 8 
 9     EXIT WHEN l_r_clob_length <= 0;
10 
11     dbms_lob.read(lob_loc => l_table_rowspan_clob,
12 
13                   amount  => l_r_amount,
14 
15                   offset  => l_r_offset_start,
16 
17                   buffer  => l_r_buffer);
18 
19     l_r_clob_length  := l_r_clob_length - l_r_amount;
20 
21     l_r_offset_start := l_r_offset_start + l_r_amount;
22 
23     IF l_r_clob_length <= 0 THEN
24 
25       --下一次循环结束
26 
27       IF l_clob_index = 1 THEN
28 
29         --第一次循环
30 
31         --写文本到一个文件,不附加任何新行字符
32 
33         fnd_file.put(fnd_file.output,
34 
35                      substr(l_r_buffer,
36 
37                             12,
38 
39                             length(l_r_buffer) - 11));
40 
41         --cux_conc_utl.out_msg(substr(l_r_buffer, 12, length(l_r_buffer)-11));
42 
43       ELSE
44 
45         --写文本到一个文件,不附加任何新行字符
46 
47         fnd_file.put(fnd_file.output,
48 
49                      substr(l_r_buffer,
50 
51                             1,
52 
53                             length(l_r_buffer) - 11));
54 
55         --cux_conc_utl.out_msg(substr(l_r_buffer, 1, length(l_r_buffer)-11));
56 
57       END IF; --IF l_clob_index = 1 THEN--第一次循环
58 
59     ELSE
60 
61       IF l_clob_index = 1 THEN
62 
63         --第一次循环
64 
65         --写文本到一个文件,不附加任何新行字符
66 
67         fnd_file.put(fnd_file.output,
68 
69                      substr(l_r_buffer,
70 
71                             12));
72 
73         --cux_conc_utl.out_msg(substr(l_r_buffer, 12));
74 
75       ELSE
76 
77         --写文本到一个文件,不附加任何新行字符
78 
79         fnd_file.put(fnd_file.output,
80 
81                      l_r_buffer);
82 
83         --cux_conc_utl.out_msg(l_r_buffer);
84 
85       END IF; --IF l_clob_index = 1 THEN --第一次循环 
86 
87     END IF; -- IF l_r_clob_length <= 0 THEN--下一次循环结束
88 
89   END LOOP;

View Code

原文链接: https://www.cnblogs.com/wang-chen/p/5756475.html

欢迎关注

微信关注下方公众号,第一时间获取干货硬货;公众号内回复【pdf】免费获取数百本计算机经典书籍

原创文章受到原创版权保护。转载请注明出处:https://www.ccppcoding.com/archives/238476

非原创文章文中已经注明原地址,如有侵权,联系删除

关注公众号【高性能架构探索】,第一时间获取最新文章

转载文章受原作者版权保护。转载请注明原作者出处!

(0)
上一篇 2023年2月13日 下午5:50
下一篇 2023年2月13日 下午5:51

相关推荐