1、LOB概念
大对象类型用于存储非结构化的大数据,比如大文本、图片、电影、音乐等
Oracle数据库里面的LOB有四种类型:
1、CLOB :字符大对象,存储在数据库内部;
2、NCLOB:多字节字符大对象,存储在数据库内部;
3、BLOB:二进制大对象,存储在数据库内部;
4、BFILE:二进制文件,存储在数据库外部;
2、LONG 和 LOB的区别
LONG and LONG RAW | LOB |
---|---|
Single LONG column per table | Multiple LOB columns per table |
Up to 2 GB | Up to 4 GB |
SELECT returns data | SELECT returns locator |
Data stored in-line | Data stored in-line or out-of-line |
Sequential access to data | Random access to data |
Long 和 Long RAW 是Oracle 9i以前的版本使用的大对象类型;在9i以后都建议使用 LOB,Oracle 9i 也提供了一系列函数用以从LONG 升级到LOB OUT-of-LINE 的理解: LOB可以是对象类型的属性,而LONG不行;
LOB数据的存储方式:LOB 分为 Value 和 Locator 两部分,在数据库表上的LOB字段,肯定会存储 LOB的Locator; 至于LOB的value,则要看其内外部类型和大小决定存储位置,默认情况下,内部LOB小于 4000字节会被存储在同一行上,超过部分则会存储在数据库内部的其他地方,这都有Oracle数据库自动管理。
3、内部LOB的一般操作步骤为
1、在表中添加LOB类型的列
2、在程序中声明和初始化LOB的Locator
3、使用 SELECT FOR UPDATE 锁定目标行,准备更新行上的LOB列(LOB的Locator)
4、生成LOB对象,可使用DBMS_LOB 这样的PLSQL包,也可以使用OCI,JDBC等;
5、Commit 提交更改;
4、外部LOB Bfile的操作
Bfile是数据库外部文件,在数据库表上这种类型的字段实际只是存储一个Locator;
Bfile的使用限制:Bfile是数据库外部文件,是只读的,所以不参与事务操作;用户必须先创建文件并放到 特定的目录下,给予Oracle进程以目录和文件的读取权限;
在Oracle 中删除Bfile这样的LOB数据的时候,它并没有实际的去删除对应的操作系统上的文件,实际文件 的删除是DBA,系统管理员的工作,Bfile的大小限制取决于操作系统,不受Oracle限制。
5、Oracle Directory
为了便于控制Bfile存储的安全性,Oracle 数据库引入了Oracle Directory的 概念;
在Oracle 内部创建的 Directory 默认的所有者是sys,并有DBA( 或者是另一个拥有 CREATE ANY DIRECTORY
权限的用户)创建;Directory 对象可以像表那样给其他用户赋权。
6、使用Bfile的一般步骤
1、在操作系统上创建目录,并给Oracle数据库进程赋予阅读权限,把外部文件放入这个目录
2、在Oracle数据库中表添加Bfile类型字段
ALTER TABLE employees
ADD emp_video BFILE;
3、在Oracle 数据库中创建Directory 对象
CREATE DIRECTORY dir_name
AS os_path;
4、授权读权限给特定的数据库用户
GRANT READ ON DIRECTORY dir_name TO user|role|PUBLIC;
5、往表中插入数据时使用 BFILENAME 函数,它可以关联外部文件和表上的Bfile列
FUNCTION BFILENAME (directory_alias IN VARCHAR2,
filename IN VARCHAR2)
RETURN BFILE;
6、在程序中声明和初始化LOB的Locator
7、Select 指定行上 Bfile 列 到Locator
8、使用 DBMS_LOB 或者通过 OCI 读取Bfile (使用Locator作为文件的一个引用)
CREATE OR REPLACE PROCEDURE load_emp_bfile
(p_file_loc IN VARCHAR2) IS
v_file BFILE;
v_filename VARCHAR2(16);
CURSOR emp_cursor IS
SELECT first_name FROM employees
WHERE department_id = 60 FOR UPDATE;
BEGIN
FOR emp_record IN emp_cursor LOOP
v_filename := emp_record.first_name || '.bmp';
v_file := BFILENAME(p_file_loc, v_filename);
DBMS_LOB.FILEOPEN(v_file);
UPDATE employees SET emp_video = v_file
WHERE CURRENT OF emp_cursor;
DBMS_OUTPUT.PUT_LINE('LOADED FILE: '||v_filename
|| ' SIZE: ' || DBMS_LOB.GETLENGTH(v_file));
DBMS_LOB.FILECLOSE(v_file);
END LOOP;
END load_emp_bfile;
/
7、使用DBMS_LOB.FILEEXISTS
测试文件是否存在
CREATE OR REPLACE PROCEDURE load_emp_bfile
(p_file_loc IN VARCHAR2)
IS
v_file BFILE; v_filename VARCHAR2(16);
v_file_exists BOOLEAN;
CURSOR emp_cursor IS ...
BEGIN
FOR emp_record IN emp_cursor LOOP
v_filename := emp_record.first_name || '.bmp';
v_file := BFILENAME (p_file_loc, v_filename);
v_file_exists := (DBMS_LOB.FILEEXISTS(v_file) = 1);
IF v_file_exists THEN
DBMS_LOB.FILEOPEN (v_file); ...
8、DBMS_LOB主要函数介绍
1、更改LOB的值: APPEND, COPY, ERASE, TRIM, WRITE, LOADFROMFILE
2、读取、检查LOB的值: GETLENGTH, INSTR, READ, SUBSTR
3、Bfile专用:FILECLOSE, FILECLOSEALL, FILEEXISTS, FILEGETNAME, FILEISOPEN, FILEOPEN
A.最常用的Read 和Write介绍
PROCEDURE READ (
lobsrc IN BFILE|BLOB|CLOB ,
amount IN OUT BINARY_INTEGER,
offset IN INTEGER,
buffer OUT RAW|VARCHAR2 )
PROCEDURE WRITE (
lobdst IN OUT BLOB|CLOB,
amount IN OUT BINARY_INTEGER,
offset IN INTEGER := 1,
buffer IN RAW|VARCHAR2 ) -- RAW for BLOB
9、数据库表中LOB列的增删改
下面的例子中resume是CLOB类型,Picture是BLOB类型
A.新增
INSERT INTO employees (employee_id, first_name,last_name, email,
hire_date, job_id, salary, resume, picture)
VALUES (405, 'Marvin', 'Ellis', 'MELLIS', SYSDATE, 'AD_ASST',
4000, EMPTY_CLOB(),NULL);
B.更新
UPDATE employees
SET resume = 'Date of Birth: 8 February 1951',
picture = EMPTY_BLOB()
WHERE employee_id = 405;
UPDATE employees
SET resume = 'Date of Birth: 1 June 1956'
WHERE employee_id = 170;
注意: **EMPTY_CLOB()**
,**EMPTY_BLOB()**
跟NULL是不同的概念,ISNULL 对这两种情况返回FALSE
DECLARE
lobloc CLOB; -- serves as the LOB locator
text VARCHAR2(32767):='Resigned: 5 August 2000';
amount NUMBER ; -- amount to be written
offset INTEGER; -- where to start writing
BEGIN
SELECT resume INTO lobloc
FROM employees
WHERE employee_id = 405 FOR UPDATE;
offset := DBMS_LOB.GETLENGTH(lobloc) + 2;
amount := length(text);
DBMS_LOB.WRITE (lobloc, amount, offset, text );
text := ' Resigned: 30 September 2000';
SELECT resume INTO lobloc
FROM employees
WHERE employee_id = 170 FOR UPDATE;
amount := length(text);
DBMS_LOB.WRITEAPPEND(lobloc, amount, text);
COMMIT;
END;
C.查询
SELECT employee_id, last_name , resume -- CLOB
FROM employees
WHERE employee_id IN (405, 170);
LOB内容截取常用函数
DBMS_LOB.SUBSTR(lob_column, no_of_chars, starting)
DBMS_LOB.INSTR (lob_column, pattern)
SELECT DBMS_LOB.SUBSTR (resume, 5, 18),
DBMS_LOB.INSTR (resume,' = ')
FROM employees
WHERE employee_id IN (170, 405);
D.删除
DELETE
FROM employees
WHERE employee_id = 405;
删除一行的时候,该行上的内部LOB对象也被删除。 如果只是想删除LOB列,而不想删除整行的数据,那么应该使用UPDATE 语句,是LOB列=NULL 或者 EMPTY_C/BLOB();
UPDATE employees
SET resume = EMPTY_CLOB()
WHERE employee_id = 170;