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 employeesADD emp_video BFILE;
3、在Oracle 数据库中创建Directory 对象
CREATE DIRECTORY dir_nameAS 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) ISv_file BFILE;v_filename VARCHAR2(16);CURSOR emp_cursor ISSELECT first_name FROM employeesWHERE department_id = 60 FOR UPDATE;BEGINFOR emp_record IN emp_cursor LOOPv_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_fileWHERE 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)ISv_file BFILE; v_filename VARCHAR2(16);v_file_exists BOOLEAN;CURSOR emp_cursor IS ...BEGINFOR emp_record IN emp_cursor LOOPv_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 THENDBMS_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 employeesSET resume = 'Date of Birth: 8 February 1951',picture = EMPTY_BLOB()WHERE employee_id = 405;
UPDATE employeesSET resume = 'Date of Birth: 1 June 1956'WHERE employee_id = 170;
注意: **EMPTY_CLOB()**,**EMPTY_BLOB()** 跟NULL是不同的概念,ISNULL 对这两种情况返回FALSE
DECLARElobloc CLOB; -- serves as the LOB locatortext VARCHAR2(32767):='Resigned: 5 August 2000';amount NUMBER ; -- amount to be writtenoffset INTEGER; -- where to start writingBEGINSELECT resume INTO loblocFROM employeesWHERE 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 loblocFROM employeesWHERE employee_id = 170 FOR UPDATE;amount := length(text);DBMS_LOB.WRITEAPPEND(lobloc, amount, text);COMMIT;END;
C.查询
SELECT employee_id, last_name , resume -- CLOBFROM employeesWHERE 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 employeesWHERE employee_id IN (170, 405);
D.删除
DELETEFROM employeesWHERE employee_id = 405;
删除一行的时候,该行上的内部LOB对象也被删除。 如果只是想删除LOB列,而不想删除整行的数据,那么应该使用UPDATE 语句,是LOB列=NULL 或者 EMPTY_C/BLOB();
UPDATE employeesSET resume = EMPTY_CLOB()WHERE employee_id = 170;
